@version 1 condition triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount), as: [ token_transfers: ( valid_amounts? = false valid_liquidity? = false user_amounts = get_user_transfers_amount(transaction) if user_amounts.token1 > 0 && user_amounts.token2 > 0 && user_amounts.token1 >= token1_min_amount && user_amounts.token2 >= token2_min_amount do lp_token_supply = State.get("lp_token_supply", 0) reserves = State.get("reserves", [token1: 0, token2: 0]) final_amounts = nil if lp_token_supply != 0 do # Returns final_amounts.token1 == 0 in case of insufficient funds final_amounts = get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount) else final_amounts = [token1: user_amounts.token1, token2: user_amounts.token2] end if final_amounts.token1 > 0 && final_amounts.token2 > 0 do valid_amounts? = true pool_balances = get_pool_balances() # Amount = final amounts + potential current balance over reserve token1_amount = final_amounts.token1 + (pool_balances.token1 - reserves.token1) token2_amount = final_amounts.token2 + (pool_balances.token2 - reserves.token2) lp_token_to_mint = get_lp_token_to_mint(token1_amount, token2_amount) valid_liquidity? = lp_token_to_mint > 0 end end valid_amounts? && valid_liquidity? ) ] 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 = pool_balances.token1 - reserves.token1 - token1_to_refund token2_amount = pool_balances.token2 - reserves.token2 - token2_to_refund lp_token_to_mint = get_lp_token_to_mint(token1_amount, token2_amount) 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: 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF, recipients: [ [to: transaction.address, amount: lp_token_to_mint_bigint] ] ] new_token1_reserve = pool_balances.token1 - token1_to_refund new_token2_reserve = 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: "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4") 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)) end condition triggered_by: transaction, on: remove_liquidity(), as: [ token_transfers: ( valid? = false user_amount = get_user_lp_amount(transaction.token_transfers) lp_token_supply = State.get("lp_token_supply", 0) if user_amount > 0 && 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 valid? = token1_to_remove > 0 && token2_to_remove > 0 end valid? ) ] actions triggered_by: transaction, on: remove_liquidity() do user_amount = get_user_lp_amount(transaction.token_transfers) pool_balances = get_pool_balances() lp_token_supply = State.get("lp_token_supply") token1_to_remove = (user_amount * pool_balances.token1) / lp_token_supply token2_to_remove = (user_amount * pool_balances.token2) / lp_token_supply 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: "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4") 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 condition triggered_by: transaction, on: swap(min_to_receive), as: [ token_transfers: ( valid? = false transfer = get_user_transfer(transaction) if transfer != nil do swap = get_swap_infos(transfer.token_address, transfer.amount) valid? = swap.output_amount > 0 && swap.output_amount >= min_to_receive end valid? ) ] actions triggered_by: transaction, on: swap(_min_to_receive) do transfer = get_user_transfer(transaction) swap = get_swap_infos(transfer.token_address, transfer.amount) 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 == "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4" do pool_balances = Map.set(pool_balances, "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 = Map.set(pool_balances, "token1", pool_balances.token1 - swap.output_amount) token_to_send = "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4" 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: 0x0000CFC185E5836BDC967B1DF7E8C0D3D61A0F7B1101AA077A7B8E307C33310D0D2B, amount: swap.protocol_fee) else Contract.add_token_transfer(to: 0x0000CFC185E5836BDC967B1DF7E8C0D3D61A0F7B1101AA077A7B8E307C33310D0D2B, amount: swap.protocol_fee, token_address: transfer.token_address) 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) == 0x000066CD867DA536A73D39CF05174387923358DC0009A29CC7162D4AED00675DAB55 ) ] actions triggered_by: transaction, on: update_code() do params = [ "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4", "UCO", 0x0000818EF23676779DAE1C97072BB99A3E0DD1C31BAD3787422798DBE3F777F74A43, 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF ] new_code = Contract.call_function(0x000086E60124C986EBCAA5AFFB7A3DB8213072A132233FE61CF45651FDCF3C4CECEA, "get_pool_code", params) if Code.is_valid?(new_code) && !Code.is_same?(new_code, contract.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: ( # Pool code can only be updated from the master 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) == 0x0000E46F8E90074DDF1DFC46385E07D826D35251F3A7B7FF65AD6F7E4B138AFF7C10 ) ] actions triggered_by: transaction, on: set_protocol_fee(new_protocol_fee) do State.set("protocol_fee", new_protocol_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 == "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4" 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 == "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4" 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_swap_infos(token_address, amount) do output_amount = 0 fee = 0 protocol_fee = 0 price_impact = 0 reserves = State.get("reserves", [token1: 0, token2: 0]) token_address = String.to_uppercase(token_address) if reserves.token1 > 0 && reserves.token2 > 0 do fee = amount * 0.0025 protocol_fee = amount * State.get("protocol_fee", 0.25) / 100 amount_with_fee = amount - fee - protocol_fee market_price = 0 if token_address == "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4" do market_price = amount_with_fee * (reserves.token2 / reserves.token1) amount = (amount_with_fee * reserves.token2) / (amount_with_fee + reserves.token1) if amount < reserves.token2 do output_amount = amount end else market_price = amount_with_fee * (reserves.token1 / reserves.token2) amount = (amount_with_fee * reserves.token1) / (amount_with_fee + reserves.token2) if amount < reserves.token1 do output_amount = amount end end if output_amount > 0 do # This check is necessary as there might be some approximation in small decimal calculation if market_price > output_amount do price_impact = ((market_price / output_amount) - 1) * 100 else price_impact = 0 end end end [ output_amount: output_amount, fee: fee, protocol_fee: 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: "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4", reserve: reserves.token1 ], token2: [ address: "UCO", reserve: reserves.token2 ], lp_token: [ address: 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF, supply: State.get("lp_token_supply", 0) ], fee: 0.25, protocol_fee: State.get("protocol_fee", 0.25), 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 = 0x0000818EF23676779DAE1C97072BB99A3E0DD1C31BAD3787422798DBE3F777F74A43 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 == "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4" 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 = 0x0000818EF23676779DAE1C97072BB99A3E0DD1C31BAD3787422798DBE3F777F74A43 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 = [ "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4", "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 = 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF 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 balances = Chain.get_balance(contract.address) token2_balance = 0 if "UCO" == "UCO" do token2_balance = balances.uco else token2_id = [token_address: "UCO", token_id: 0] token2_balance = Map.get(balances.tokens, token2_id, 0) end token1_id = [token_address: "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4", token_id: 0] [ token1: Map.get(balances.tokens, token1_id, 0), token2: token2_balance ] end
Content (0 B)
{ "lp_token_supply": 9276.39381855, "reserves": { "token1": 64.53136176, "token2": 1021524.56312587 }, "stats": { "token1_total_fee": 0.07914467, "token1_total_protocol_fee": 0.07914467, "token1_total_volume": 31.65797812, "token2_total_fee": 980.02575747, "token2_total_protocol_fee": 980.02575747, "token2_total_volume": 392010.30317095 } }
-
Secret shared with 1 key
Encoded secret
AC8F7C796D864ACBAA0E1DD6839F088F91765375DE257826AE21D0D53E477203A58F9A05702214F1F06CD29B7922E02E694887693B439317316C7CA6
Authorized keys
- 00017877BCF4122095926A49489009649603AB129822A19EF9D573B8FD714911ED7F
Contract recipients (0)
Inputs (0)
Contract inputs (0)
Unspent outputs (2)
-
From 0000AFC4...AB6BAt 2024-02-28 17:15:47 UTCAmount 1,021,524.56312587 UCO
-
From 0000AFC4...AB6BAt 2024-02-28 17:15:47 UTCAmount 64.53115254 00003DF6...73B4
Previous public key
0001415F763FBA1B446CABA25EBC4F5707C98FDE493B64186C481234BC8C3C4F435E
Previous signature
FA2247ED78A7217F0835E3F590D460429379AFAD8B7AD0B5EE3C2A9F126F83E3668DFBE9106B07A34F0C019C8BFCC8CF586B2D08399BAEF5C431CC011A64A300
Origin signature
3045022100CE7B7D15B4E5B5EAD5A0545A467EC8293FA8F12F807416F8C95DA18D0D3B5E830220435E92CE01FE1509D9613EB4E83A19C9391A435795AAAC0022F9DCD306FF9D88
Proof of work
010104AB672F1E69B064D192819F1797C1926F158DBA8F3924AC732B4C4D70D0C8EA0A0D6506E5896C9C2524D2BE26CB5016287E1816A597C408008BA36FCB154A7765
Proof of integrity
002ECD1508032CEB1C0026195DB068F9547DA2C3E01622B1584B397DE6A54A373B
Coordinator signature
0D8522FAE3FB239B20E0463E26F55085B4C9FCC0FC96A9607B67C39A4FDB5CE1E8D97E1F230B225DF4DA22E69B9F349EB4F7DC16C8E98F564CEE6AD3F498EF0E
Validator #1 public key
000177BA744AC778DC2D51A1B7C622E7AC4BD1E1AA8DA2D0FCE71BAAB7DAD0E020E0
Validator #1 signature
4F062742ADF2C6AACE5C74FA1E1B273A7CED38AF2C0A82BED0E237E1A1D85318BC6CCABBE1AC954AB5D3FF932911502D1E01A1B93BDC025D41F76B3D745F4A04
Validator #2 public key
00010F2A0E4C424582A94BD90E05FE6931628F91988ABBE387D365994F1F3FCF5A12
Validator #2 signature
84A5DBA1B393771793649DED7C0B43A325884BD0600279BE48EDF7013F9F5CE50D88E9AE889E908539E8FB0E2036A738F367A11127B9B613EBD48A0AF7FC2506
Validator #3 public key
000151C124A6211CD402FD1CFE560C5DB51ED0CBEF44B09B21A41206028E7E5942BF
Validator #3 signature
5F18D2CECBA8CC5E62F2C360EC1A438BAE28924954FA81C6E063D7A5F89671FCF6E6D9EBAA8CED817126540D37A16705E43B438CA231403C2C49F84824C65D0F
Validator #4 public key
00011B58ED42235461734EAF253BD97A80B92899ABCC3BE680D44B6825DD2A88A947
Validator #4 signature
2650FEEA2EA622D751825506A4482BCE6DAAAEDA3251B251D99E5B0A37898B0ED6461D3D5E8E0383101659E953CF17084849471BB7F817823E6FFC7F94413B06
Validator #5 public key
000162E6ADFF9FBBBC4BDBB3CD56A5A13A1E8576C3619ADC58A189F7E9A3A77FF95D
Validator #5 signature
F56888E69E84FF1DD94E762E65273B816F3C5AC3E97CAF25566ECB4A668AEB06D9AAD16C35198EA4DCDEBF2156E589ECB9CEC2B215A8C4809EB5F44FBAD2D60E