@version 1 condition triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount), as: [ token_transfers: ( user_amounts = get_user_transfers_amount(transaction) valid_transfers? = user_amounts.token1 > 0 && user_amounts.token2 > 0 valid_min? = user_amounts.token1 >= token1_min_amount && user_amounts.token2 >= token2_min_amount valid_transfers? && valid_min? ) ] actions triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount) do pool_balances = get_pool_balances() user_amounts = get_user_transfers_amount(transaction) lp_token_supply = State.get("lp_token_supply", 0) reserves = State.get("reserves", [token1: 0, token2: 0]) final_amounts = get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount) token1_to_refund = user_amounts.token1 - final_amounts.token1 token2_to_refund = user_amounts.token2 - final_amounts.token2 token1_amount = user_amounts.token1 + pool_balances.token1 - reserves.token1 - token1_to_refund token2_amount = user_amounts.token2 + pool_balances.token2 - reserves.token2 - token2_to_refund lp_token_to_mint = get_lp_token_to_mint(token1_amount, token2_amount) # Handle invalid values and refund user valid_amounts? = final_amounts.token1 > 0 && final_amounts.token2 > 0 valid_liquidity? = lp_token_to_mint > 0 if valid_amounts? && valid_liquidity? do lp_token_to_mint_bigint = Math.trunc(lp_token_to_mint * 100_000_000) # Remove minimum liquidity if this is the first liquidity if the pool # First liquidity minted and burned on pool creation if lp_token_supply == 0 do lp_token_to_mint_bigint = lp_token_to_mint_bigint - 10 end token_specification = [ aeip: [8, 18, 19], supply: lp_token_to_mint_bigint, token_reference: 0x0000D1B4A0597A033F7DD0C8CA274745F850A990725B7B73B5E8CEBC7C4F9EA82954, recipients: [ [to: transaction.address, amount: lp_token_to_mint_bigint] ] ] new_token1_reserve = user_amounts.token1 + pool_balances.token1 - token1_to_refund new_token2_reserve = user_amounts.token2 + pool_balances.token2 - token2_to_refund State.set("lp_token_supply", lp_token_supply + lp_token_to_mint) State.set("reserves", [token1: new_token1_reserve, token2: new_token2_reserve]) if token1_to_refund > 0 do Contract.add_token_transfer(to: transaction.address, amount: token1_to_refund, token_address: "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF") end if token2_to_refund > 0 do if "UCO" == "UCO" do Contract.add_uco_transfer(to: transaction.address, amount: token2_to_refund) else Contract.add_token_transfer(to: transaction.address, amount: token2_to_refund, token_address: "UCO") end end Contract.set_type("token") Contract.set_content(Json.to_string(token_specification)) else # Liquidity provision is invalid, refund user of it's tokens Contract.set_type("transfer") if "UCO" == "UCO" do Contract.add_uco_transfer(to: transaction.address, amount: user_amounts.token2) else Contract.add_token_transfer(to: transaction.address, amount: user_amounts.token2, token_address: "UCO") end Contract.add_token_transfer(to: transaction.address, amount: user_amounts.token1, token_address: "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF") end end condition triggered_by: transaction, on: remove_liquidity(), as: [ token_transfers: ( user_amount = get_user_lp_amount(transaction.token_transfers) user_amount > 0 ) ] actions triggered_by: transaction, on: remove_liquidity() do return? = true user_amount = get_user_lp_amount(transaction.token_transfers) lp_token_supply = State.get("lp_token_supply", 0) if lp_token_supply > 0 do pool_balances = get_pool_balances() token1_to_remove = (user_amount * pool_balances.token1) / lp_token_supply token2_to_remove = (user_amount * pool_balances.token2) / lp_token_supply if token1_to_remove > 0 && token2_to_remove > 0 do return? = false new_token1_reserve = pool_balances.token1 - token1_to_remove new_token2_reserve = pool_balances.token2 - token2_to_remove State.set("lp_token_supply", lp_token_supply - user_amount) State.set("reserves", [token1: new_token1_reserve, token2: new_token2_reserve]) Contract.set_type("transfer") Contract.add_token_transfer(to: transaction.address, amount: token1_to_remove, token_address: "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF") if "UCO" == "UCO" do Contract.add_uco_transfer(to: transaction.address, amount: token2_to_remove) else Contract.add_token_transfer(to: transaction.address, amount: token2_to_remove, token_address: "UCO") end end end if return? do # Refund is invalid, return LP tokens to user Contract.set_type("transfer") Contract.add_token_transfer(to: transaction.address, amount: user_amount, token_address: 0x0000D1B4A0597A033F7DD0C8CA274745F850A990725B7B73B5E8CEBC7C4F9EA82954) end end condition triggered_by: transaction, on: swap(_min_to_receive), as: [ token_transfers: ( transfer = get_user_transfer(transaction) transfer != nil ) ] actions triggered_by: transaction, on: swap(min_to_receive) do transfer = get_user_transfer(transaction) swap = get_output_swap_infos(transfer.token_address, transfer.amount) if swap.output_amount > 0 && swap.output_amount >= min_to_receive do pool_balances = get_pool_balances() token_to_send = nil token1_volume = 0 token2_volume = 0 token1_fee = 0 token2_fee = 0 token1_protocol_fee = 0 token2_protocol_fee = 0 if transfer.token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do pool_balances = [ token1: pool_balances.token1 + transfer.amount - swap.protocol_fee, token2: pool_balances.token2 - swap.output_amount ] token_to_send = "UCO" token1_volume = transfer.amount token1_fee = swap.fee token1_protocol_fee = swap.protocol_fee else pool_balances = [ token1: pool_balances.token1 - swap.output_amount, token2: pool_balances.token2 + transfer.amount - swap.protocol_fee ] token_to_send = "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" token2_volume = transfer.amount token2_fee = swap.fee token2_protocol_fee = swap.protocol_fee end State.set("reserves", [token1: pool_balances.token1, token2: pool_balances.token2]) stats = State.get("stats", [ token1_total_fee: 0, token2_total_fee: 0, token1_total_volume: 0, token2_total_volume: 0, token1_total_protocol_fee: 0, token2_total_protocol_fee: 0, ]) token1_total_fee = Map.get(stats, "token1_total_fee") + token1_fee token2_total_fee = Map.get(stats, "token2_total_fee") + token2_fee token1_total_volume = Map.get(stats, "token1_total_volume") + token1_volume token2_total_volume = Map.get(stats, "token2_total_volume") + token2_volume token1_total_protocol_fee = Map.get(stats, "token1_total_protocol_fee") + token1_protocol_fee token2_total_protocol_fee = Map.get(stats, "token2_total_protocol_fee") + token2_protocol_fee stats = Map.set(stats, "token1_total_fee", token1_total_fee) stats = Map.set(stats, "token2_total_fee", token2_total_fee) stats = Map.set(stats, "token1_total_volume", token1_total_volume) stats = Map.set(stats, "token2_total_volume", token2_total_volume) stats = Map.set(stats, "token1_total_protocol_fee", token1_total_protocol_fee) stats = Map.set(stats, "token2_total_protocol_fee", token2_total_protocol_fee) State.set("stats", stats) Contract.set_type("transfer") if token_to_send == "UCO" do Contract.add_uco_transfer(to: transaction.address, amount: swap.output_amount) else Contract.add_token_transfer(to: transaction.address, amount: swap.output_amount, token_address: token_to_send) end if swap.protocol_fee > 0 do if transfer.token_address == "UCO" do Contract.add_uco_transfer(to: 0x0000CC1FADBD31B043947C016E09CCD59BC3C81E55AB8A4932A046236D5E0FEE9E45, amount: swap.protocol_fee) else Contract.add_token_transfer(to: 0x0000CC1FADBD31B043947C016E09CCD59BC3C81E55AB8A4932A046236D5E0FEE9E45, amount: swap.protocol_fee, token_address: transfer.token_address) end end else # Swap is invalid, return tokens to user Contract.set_type("transfer") if transfer.token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do Contract.add_token_transfer(to: transaction.address, amount: transfer.amount, token_address: "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF") else if transfer.token_address == "UCO" do Contract.add_uco_transfer(to: transaction.address, amount: transfer.amount) else Contract.add_token_transfer(to: transaction.address, amount: transfer.amount, token_address: "UCO") end end end end condition triggered_by: transaction, on: update_code(), as: [ previous_public_key: ( # Pool code can only be updated from the router contract of the dex # Transaction is not yet validated so we need to use previous address # to get the genesis address previous_address = Chain.get_previous_address() Chain.get_genesis_address(previous_address) == 0x000077CEC9D9DBC0183CAF843CBB4828A932BB1457E382AC83B31AD6F9755DD50FFC ) ] actions triggered_by: transaction, on: update_code() do params = [ "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF", "UCO", 0x000090C5AFCC97C2357E964E3DDF5BE9948477F7C1DE2C633CDFC95B202970AEA036, 0x0000D1B4A0597A033F7DD0C8CA274745F850A990725B7B73B5E8CEBC7C4F9EA82954 ] new_code = Contract.call_function(0x00004CE47B2828E923EB679FEF311DD458AA0571C67DB5CB46B4E0793CAC525AC791, "get_pool_code", params) if Code.is_valid?(new_code) do Contract.set_type("contract") Contract.set_code(new_code) end end condition triggered_by: transaction, on: set_protocol_fee(new_protocol_fee), as: [ content: new_protocol_fee <= 1 && new_protocol_fee >= 0, previous_public_key: ( previous_address = Chain.get_previous_address() Chain.get_genesis_address(previous_address) == 0x0000BE4D33FC48CD4791A58EF7296F6916F5A2032A4E66111CF10521D08FC660A4D3 ) ] actions triggered_by: transaction, on: set_protocol_fee(new_protocol_fee) do State.set("protocol_fee", new_protocol_fee) end condition triggered_by: transaction, on: set_lp_fee(new_lp_fee), as: [ content: new_lp_fee <= 1 && new_lp_fee >= 0, previous_public_key: ( previous_address = Chain.get_previous_address() Chain.get_genesis_address(previous_address) == 0x0000BE4D33FC48CD4791A58EF7296F6916F5A2032A4E66111CF10521D08FC660A4D3 ) ] actions triggered_by: transaction, on: set_lp_fee(new_lp_fee) do State.set("lp_fee", new_lp_fee) end export fun get_ratio(token_address) do reserves = State.get("reserves", [token1: 0, token2: 0]) ratio = 0 token_address = String.to_uppercase(token_address) if reserves.token1 > 0 && reserves.token2 > 0 do if token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do ratio = reserves.token2 / reserves.token1 else ratio = reserves.token1 / reserves.token2 end end ratio end export fun get_equivalent_amount(token_address, amount) do reserves = State.get("reserves", [token1: 0, token2: 0]) ratio = 0 token_address = String.to_uppercase(token_address) if reserves.token1 > 0 && reserves.token2 > 0 do if token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do ratio = reserves.token2 / reserves.token1 else ratio = reserves.token1 / reserves.token2 end end amount * ratio end export fun get_lp_token_to_mint(token1_amount, token2_amount) do lp_token_supply = State.get("lp_token_supply", 0) reserves = State.get("reserves", [token1: 0, token2: 0]) if lp_token_supply == 0 || reserves.token1 == 0 || reserves.token2 == 0 do # First liquidity Math.sqrt(token1_amount * token2_amount) else mint_amount1 = (token1_amount * lp_token_supply) / reserves.token1 mint_amount2 = (token2_amount * lp_token_supply) / reserves.token2 if mint_amount1 < mint_amount2 do mint_amount1 else mint_amount2 end end end export fun get_output_swap_infos(token_address, input_amount) do if input_amount <= 0 do throw code: 1, message: "input amount must be positive" end reserves = State.get("reserves", [token1: 0, token2: 0]) if reserves.token1 <= 0 || reserves.token2 <= 0 do throw code: 2, message: "Insufficient output liquidity" end output_amount = 0 price_impact = 0 market_price = 0 token_address = String.to_uppercase(token_address) fee = input_amount * State.get("lp_fee", 0.3) / 100 protocol_fee = input_amount * State.get("protocol_fee", 0) / 100 amount_with_fee = input_amount - fee - protocol_fee if token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do market_price = reserves.token2 / reserves.token1 amount = (amount_with_fee * reserves.token2) / (amount_with_fee + reserves.token1) if amount < reserves.token2 do output_amount = amount else throw code: 2, message: "Insufficient output liquidity" end else market_price = reserves.token1 / reserves.token2 amount = (amount_with_fee * reserves.token1) / (amount_with_fee + reserves.token2) if amount < reserves.token1 do output_amount = amount else throw code: 2, message: "Insufficient output liquidity" end end # This check is necessary as there might be some approximation in small decimal calculation output_price = output_amount / input_amount if output_amount > 0 && market_price > output_price do price_impact = 100 - (output_price * 100 / market_price) end [ output_amount: output_amount, fee: fee, protocol_fee: protocol_fee, price_impact: price_impact ] end export fun get_input_swap_infos(token_address, output_amount) do if output_amount < 0 do throw code: 1, message: "output amount cannot be negative" end reserves = State.get("reserves", [token1: 0, token2: 0]) token_address = String.to_uppercase(token_address) if token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" && output_amount >= reserves.token1 do throw code: 2, message: "Insufficient output liquidity" end if token_address == "UCO" && output_amount >= reserves.token2 do throw code: 2, message: "Insufficient output liquidity" end input_amount = 0 market_price = 0 lp_fee = State.get("lp_fee", 0.3) / 100 protocol_fee = State.get("protocol_fee", 0) / 100 price_impact = 0 if token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do market_price = reserves.token1 / reserves.token2 input_amount = (output_amount * reserves.token2) / ((reserves.token1 - output_amount) * (1 - lp_fee - protocol_fee)) else market_price = reserves.token2 / reserves.token1 input_amount = (output_amount * reserves.token1) / ((reserves.token2 - output_amount) * (1 - lp_fee - protocol_fee)) end if input_amount > 0 do # This check is necessary as there might be some approximation in small decimal calculation output_price = output_amount / input_amount if market_price > output_price do price_impact = 100 - (output_price * 100 / market_price) end end [ input_amount: input_amount, fee: input_amount * lp_fee, protocol_fee: input_amount * protocol_fee, price_impact: price_impact ] end export fun get_remove_amounts(lp_token_amount) do reserves = State.get("reserves", [token1: 0, token2: 0]) lp_token_supply = State.get("lp_token_supply", 0) token1_to_remove = 0 token2_to_remove = 0 if lp_token_supply > 0 && lp_token_amount < lp_token_supply do token1_to_remove = (lp_token_amount * reserves.token1) / lp_token_supply token2_to_remove = (lp_token_amount * reserves.token2) / lp_token_supply end [token1: token1_to_remove, token2: token2_to_remove] end export fun get_pool_infos() do reserves = State.get("reserves", [token1: 0, token2: 0]) stats = State.get("stats", [ token1_total_fee: 0, token2_total_fee: 0, token1_total_volume: 0, token2_total_volume: 0, token1_total_protocol_fee: 0, token2_total_protocol_fee: 0, ]) [ token1: [ address: "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF", reserve: reserves.token1 ], token2: [ address: "UCO", reserve: reserves.token2 ], lp_token: [ address: 0x0000D1B4A0597A033F7DD0C8CA274745F850A990725B7B73B5E8CEBC7C4F9EA82954, supply: State.get("lp_token_supply", 0) ], fee: State.get("lp_fee", 0.3), protocol_fee: State.get("protocol_fee", 0), stats: stats ] end fun get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount) do final_token1_amount = 0 final_token2_amount = 0 if reserves.token1 > 0 && reserves.token2 > 0 do token2_ratio = reserves.token2 / reserves.token1 token2_equivalent_amount = user_amounts.token1 * token2_ratio if token2_equivalent_amount <= user_amounts.token2 && token2_equivalent_amount >= token2_min_amount do final_token1_amount = user_amounts.token1 final_token2_amount = token2_equivalent_amount else token1_ratio = reserves.token1 / reserves.token2 token1_equivalent_amount = user_amounts.token2 * token1_ratio if token1_equivalent_amount <= user_amounts.token1 && token1_equivalent_amount >= token1_min_amount do final_token1_amount = token1_equivalent_amount final_token2_amount = user_amounts.token2 end end else # No reserve final_token1_amount = user_amounts.token1 final_token2_amount = user_amounts.token2 end [token1: final_token1_amount, token2: final_token2_amount] end fun get_user_transfers_amount(tx) do contract_address = 0x000090C5AFCC97C2357E964E3DDF5BE9948477F7C1DE2C633CDFC95B202970AEA036 token1_amount = 0 token2_amount = 0 transfers = Map.get(tx.token_transfers, contract_address, []) uco_amount = Map.get(tx.uco_transfers, contract_address) if uco_amount != nil do transfers = List.prepend(transfers, [token_address: "UCO", amount: uco_amount]) end if List.size(transfers) == 2 do for transfer in transfers do if transfer.token_address == "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF" do token1_amount = transfer.amount end if transfer.token_address == "UCO" do token2_amount = transfer.amount end end end [token1: token1_amount, token2: token2_amount] end fun get_user_transfer(tx) do contract_address = 0x000090C5AFCC97C2357E964E3DDF5BE9948477F7C1DE2C633CDFC95B202970AEA036 token_transfer = nil transfers = Map.get(tx.token_transfers, contract_address, []) uco_amount = Map.get(tx.uco_transfers, contract_address) if uco_amount != nil do transfers = List.prepend(transfers, [token_address: "UCO", amount: uco_amount]) end transfer = List.at(transfers, 0) tokens = [ "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF", "UCO" ] if List.size(transfers) == 1 && List.in?(tokens, transfer.token_address) do token_transfer = transfer end token_transfer end fun get_user_lp_amount(token_transfers) do lp_token = 0x0000D1B4A0597A033F7DD0C8CA274745F850A990725B7B73B5E8CEBC7C4F9EA82954 lp_amount = 0 transfers = Map.get(token_transfers, Chain.get_burn_address(), []) for transfer in transfers do if transfer.token_address == lp_token do lp_amount = transfer.amount end end lp_amount end fun get_pool_balances() do token2_balance = 0 if "UCO" == "UCO" do token2_balance = contract.balance.uco else token2_id = [token_address: "UCO", token_id: 0] token2_balance = Map.get(contract.balance.tokens, token2_id, 0) end token1_id = [token_address: "0000457EACA7FBAA96DB4A8D506A0B69684F546166FBF3C55391B1461907EFA58EAF", token_id: 0] [ token1: Map.get(contract.balance.tokens, token1_id, 0), token2: token2_balance ] end
Content (0 B)
{ "lp_fee": 0, "lp_token_supply": 55592.31845384, "protocol_fee": 0.3, "reserves": { "token1": 119.64460572, "token2": 26037874.5325445 }, "stats": { "token1_total_fee": 0.22957848, "token1_total_protocol_fee": 1.69489578, "token1_total_volume": 619.05401085, "token2_total_fee": 51672.1377832, "token2_total_protocol_fee": 309791.77967897, "token2_total_volume": 115747960.9581222 } }
-
Secret shared with 1 key
Encoded secret
8F3B41A7D5E9A11357E32CBE52CA970DF594DE5E5EB002CF3A957E41A2F3EA988BC3400E4A9BF5F40A67C224F312E9361F38AB1734DE7FA69B14B95B
Authorized keys
- 000122A6CD9ED07E46835D6E88E5BD0BEE84C3F5E5DBF8E916AD9B2EC912C44AFEC2
Contract recipients (0)
Inputs (0)
Contract inputs (0)
Unspent outputs (2)
-
From 00006A8A...A3C8At 2025-01-29 09:30:46 UTCAmount 26,037,874.5325445 UCO
-
From 00006A8A...A3C8At 2025-01-29 09:30:46 UTCAmount 119.64460572 0000457E...8EAF
Previous public key
0001749127BFA9A4AA3ADDB24BBC79A1FBC99302A833B76DC09B15368DBE029FEBF5
Previous signature
E70D19F62110A664CF15C7480D9DC094BBE1C781AF7C3B33B992AAFDDAAE1E830A3E9F28D919DB9E42C5DED8E0251CE6FB184EE955B222160B862F7E5B0A0A03
Origin signature
304502204C1E26CFDFA98415C340BF8D8108C795E2BBA6DCD53490528BC0FDFDC9C45A3F022100EB42819ABC7EE05AC94D63838E10FBDD24F79E9412B3D6DECDA59B382CE387B4
Proof of work
010104641D2D652B2A36CDE32EABB7AC1D6F0351A1CFAE45BA1483ADAD99B166DB289E9E408C13C28D10F62F068EE552C651FAA5A2BD6417D68EAFC8C269FBD2FBE9E3
Proof of integrity
00216AAB3F6418347AF60E080704B4F3AB912AEAC6D1A3F2F7641C6E3BE53406F0
Coordinator signature
3210E560C74600CCB98EC2F4BCD7964B1BADED6ED16D38C99B23A6682618DC960C86B97CEA4888EF46F3586DAE3138C9711E520736D7150E640D14D209CF540A
Validator #1 public key
00018106B590A190EC5E85CF8FB99F7967CB4D24FFB1FD5A903BF101E9D668C2ABB1
Validator #1 signature
F0327B90D31025D37129CF87F1D1F650B76F52D095642B7321D9C0FBC5346D20A66785AD1BF6D25BCEB1AD01B07B18C1FE4D9FD8525FA0E9F40E95D92B3BDC0A
Validator #2 public key
0001D9711BA3565FCB17BEE7A45EFD5B558494A658827403D5853D454F501C5FDDFC
Validator #2 signature
FD5A75BE979A5DA37150DDC6BDEDFDCAF49B7DB6C16BD834BDDEC570843B8A9CD0F52A8F7354BA3E2270A342B21E54AD3850CEC60D1029C890F1BFE030AF5B0C
Validator #3 public key
0001A5F6705AFE5C9103B4BE3307F94B3EC386283B77ABAA1D39C423EA4D6597F989
Validator #3 signature
9841E5887D13C3DFE9A263E1E5CC2D51E948DF670084954F3C4C12C8A7BEA1B66687DD4914F254246AF91B87DA16E5DFF46D5E3CDC7A729EDAA7411912B06806
Validator #4 public key
000105B4FDF46B9FE90C30A471DCE4D296CCCDC27242C6CDA6E48622F4330C646100
Validator #4 signature
B787593A0691D532C41050B9F26B8CEA16565BF424BEB63ED1A735CF634908BA47B10817854DEE1CBB7D94BE45C463EA8A8B76985C675A2C7F604450B98CC50F
Validator #5 public key
000134CE600B5903D5A9EAC69B4E0944FDCCED2CC5A84BC2D6780991744A7BA933D3
Validator #5 signature
9334E2448B24E0E543DBA3228E32710E8973484FD1892259B763ECF04B772B11EA40C24610C486248AA5BC5B0E26CF850B302773424D09E08426F110696DAC00