Type
CONTRACT
Validation date
2024-01-31 14:39:45 UTC
Fee
0 UCO

Code (1.92 KB)

@version 1

condition triggered_by: transaction, on: add_pool(token1_address, token2_address, pool_creation_address), as: [
  type: "transfer",
  content: (
    valid? = false

    token1_address = String.to_uppercase(token1_address)
    token2_address = String.to_uppercase(token2_address)
    pool_creation_address = String.to_hex(pool_creation_address)

    pool_exists? = get_pool_addresses(token1_address, token2_address) != nil

    if token1_address != token2_address && !pool_exists? do
      # Could create a new function Chain.get_transactions(list_of_address)
      pool_transaction = Chain.get_transaction(pool_creation_address)

      # Ensure tokens exists and lp token definition is good
      valid_token1? = valid_token?(token1_address)
      valid_token2? = valid_token?(token2_address)

      valid_definition? = false
      if valid_token1? && valid_token2? && pool_transaction != nil && pool_transaction.type == "token" do
        expected_content = Contract.call_function(
          0x000086e60124c986ebcaa5affb7a3db8213072a132233fe61cf45651fdcf3c4cecea,
          "get_lp_token_definition",
          [token1_address, token2_address]
        )

        valid_definition? = Json.parse(pool_transaction.content) == Json.parse(expected_content)
      end

      valid_code? = false
      pool_genesis_address = nil
      if valid_definition? do
        # Ensure code is valid
        pool_genesis_address = Chain.get_genesis_address(pool_creation_address)
        expected_code = Contract.call_function(
          0x000086e60124c986ebcaa5affb7a3db8213072a132233fe61cf45651fdcf3c4cecea,
          "get_pool_code",
          [token1_address, token2_address, pool_genesis_address, pool_creation_address]
        )

        valid_code? = Code.is_same?(pool_transaction.code, expected_code)
      end

      if valid_code? do
        # Ensure liquidity is provided to the pool
        valid? = List.in?(transaction.recipients, pool_genesis_address)
      end
    end

    valid?
  )
]

actions triggered_by: transaction, on: add_pool(token1_address, token2_address, pool_creation_address) do
  token1_address = String.to_uppercase(token1_address)
  token2_address = String.to_uppercase(token2_address)
  pool_creation_address = String.to_hex(pool_creation_address)

  pool_genesis_address = Chain.get_genesis_address(pool_creation_address)
  pool_id = get_pool_id(token1_address, token2_address)
  pools = State.get("pools", Map.new())

  pool_data = [
    address: pool_genesis_address,
    lp_token_address: pool_creation_address
  ]

  pools = Map.set(pools, pool_id, pool_data)

  State.set("pools", pools)
end

condition triggered_by: transaction, on: add_farm(lp_token, start_date, end_date, reward_token, farm_creation_address), as: [
  address: (
    # Farm can only be created by the master chain 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(transaction)
    Chain.get_genesis_address(previous_address) == 0x0000e46f8e90074ddf1dfc46385e07d826d35251f3a7b7ff65ad6f7e4b138aff7c10
  ),
  content: (
    lp_token = String.to_hex(lp_token)
    reward_token = String.to_uppercase(reward_token)
    farm_creation_address = String.to_hex(farm_creation_address)

    # LP token should be listed on dex
    lp_token_exists? = false
    pools = State.get("pools", Map.new()) 
    for pool in Map.values(pools) do
      if String.to_hex(pool.lp_token_address) == lp_token do
        lp_token_exists? = true
      end
    end

    # Start date should be between 2 hours and 1 week from now
    # End date should be between 1 month (30 days) and 1 year (365 days) from start date
    valid_date? = false
    if lp_token_exists? do
      now = Time.now()
      valid_start_date? = now + 7200 <= start_date && now + 604800 >= start_date
      valid_end_date? = start_date + 2592000 <= end_date && start_date + 31536000 >= end_date 

      valid_date? = valid_start_date? && valid_end_date?
    end

    # Ensure farm code is valid
    valid_code? = false
    farm_genesis_address = nil
    if valid_date? do
      farm_transaction = Chain.get_transaction(farm_creation_address)
      if farm_transaction != nil && farm_transaction.type == "contract" do
        farm_genesis_address = Chain.get_genesis_address(farm_creation_address)

        expected_code = Contract.call_function(
          0x000086e60124c986ebcaa5affb7a3db8213072a132233fe61cf45651fdcf3c4cecea,
          "get_farm_code",
          [lp_token, start_date, end_date, reward_token, farm_genesis_address]
        )
        
        valid_code? = Code.is_same?(farm_transaction.code, expected_code)
      end
    end

    # Ensure this transaction adds the reward token to the farm
    valid_reward? = false
    if valid_code? do
      if reward_token == "UCO" do
        valid_reward? = Map.get(transaction.uco_transfers, farm_genesis_address) != nil
      else
        transfers = Map.get(transaction.token_transfers, farm_genesis_address)
        for transfer in transfers do
          if transfer.token_address == reward_token do
            valid_reward? = true
          end
        end
      end
    end

    lp_token_exists? && valid_date? && valid_code? && valid_reward?
  )
]

actions triggered_by: transaction, on: add_farm(lp_token, start_date, end_date, reward_token, farm_creation_address) do
  farms = State.get("farms", [])

  farm_genesis_address = Chain.get_genesis_address(farm_creation_address)

  new_farm = [
    lp_token_address: lp_token,
    start_date: start_date,
    end_date: end_date,
    reward_token: reward_token,
    address: farm_genesis_address
  ]

  farms = List.prepend(farms, new_farm)
  
  State.set("farms", farms)
end

condition triggered_by: transaction, on: update_code(new_code), as: [
  previous_public_key: (
    # Router code can only be updated from the master chain 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
  ),
  code: Code.is_valid?(new_code)
]

actions triggered_by: transaction, on: update_code(new_code) do
  Contract.set_type("contract")
  Contract.set_code(new_code)
end

condition triggered_by: transaction, on: update_pools_code(), as: [
  previous_public_key: (
    # Pool code update can only be requested from the master chain 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: update_pools_code() do
  pools = State.get("pools", Map.new())

  if Map.size(pools) > 0 do
    for pool_info in Map.values(pools) do
      Contract.add_recipient address: pool_info.address, action: "update_code", args: []
    end

    Contract.set_type("transfer")
  end
end

condition triggered_by: transaction, on: update_farms_code(), as: [
  previous_public_key: (
    # Pool code update can only be requested from the master chain 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: update_farms_code() do
  farms = State.get("farms", [])

  if List.size(farms) > 0 do
    for farm in farms do
      Contract.add_recipient address: farm.address, action: "update_code", args: []
    end

    Contract.set_type("transfer")
  end
end

fun get_pool_id(token1_address, token2_address) do
  if token1_address > token2_address do
    temp = token1_address
    token1_address = token2_address
    token2_address = temp
  end

  "#{token1_address}/#{token2_address}"
end

fun valid_token?(token_address) do
  valid? = false
  if token_address == "UCO" do
    valid? = true
  else
    tx = Chain.get_transaction(token_address)
    # Transaction must have type token
    # Token must be fungible
    if tx != nil && tx.type == "token" do
      token_definition = Json.parse(tx.content)
      valid? = token_definition.type == "fungible"
    end
  end
  valid?
end

export fun get_pool_addresses(token1_address, token2_address) do
  token1_address = String.to_uppercase(token1_address)
  token2_address = String.to_uppercase(token2_address)

  if token1_address > token2_address do
    temp = token1_address
    token1_address = token2_address
    token2_address = temp
  end

  pool_id = "#{token1_address}/#{token2_address}"

  pools = State.get("pools", Map.new())

  Map.get(pools, pool_id, nil)
end

export fun get_pool_list() do
  pools = State.get("pools", Map.new())

  list = []
  for pool_id in Map.keys(pools) do
    pool = Map.get(pools, pool_id)
    pool = Map.set(pool, "tokens", pool_id)
    list = List.prepend(list, pool)
  end
  list
end

export fun get_farm_list() do
  State.get("farms", [])
end

Content (0 B)

State (2.32 KB)

{
  "farms": [
    {
      "address": "0000208A670B5590939174D65F88140C05DDDBA63C0C920582E12162B22F3985E510",
      "end_date": 1710763200,
      "lp_token_address": "00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF",
      "reward_token": "UCO",
      "start_date": 1706720400
    }
  ],
  "pools": {
    "0000288BF6F0E12457B125DC54D2DFA4EB010BE3073CF02E10FB79B696180F55B827/UCO": {
      "address": "0000DD19DD796959B72998536F67814DCCABE156FF647E0E63E43395203908963767",
      "lp_token_address": "0000A4CAB2362A97002EE0A6DD2013BEC3AF02C4D8C392712CFBC38F3E4809B9314C"
    },
    "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4/0000908C7DD6B39760EF3A29CD4173A16DCD2183EC2AB5BCF851335DC162DE2BD060": {
      "address": "000025C64E795E4B6A029256CB648D601851B97470EC4F54CBBFD301F02D356FDD05",
      "lp_token_address": "0000E6A6DECE48C02F248EB8866FD08E83B9CE50AB5EEFB58F89BFC79E7492B3690B"
    },
    "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4/0000E06BFF011D495E21EA9D5266435BBF2B5E721464132E4D24C404F51B0AFA8699": {
      "address": "0000E691507E13F81CD7EC50453A95F447B778277653213278F20C42F74EBFF9046E",
      "lp_token_address": "000035ACC0A03D7FDCB940F5F6E4DC65384033A9731B6B57C68D82DEA45C8B4EE622"
    },
    "00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4/UCO": {
      "address": "0000818EF23676779DAE1C97072BB99A3E0DD1C31BAD3787422798DBE3F777F74A43",
      "lp_token_address": "00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF"
    },
    "0000653684A3FC48B47AD2F0DB5793FD03748FB56B8868BEC0AE091CD3968106E481/UCO": {
      "address": "0000469434BDBB816E178F0CC423AFB921802F18FFCD432BF5E8004BCE0270A65E55",
      "lp_token_address": "0000d0d1e6c5703b599aa5aa3abf443f742d908644e6e500682870a23b187d515c90"
    },
    "0000887597E85A2DF06070466A25DEF55CBE2988A8EBEB5B6F3655F7444B4BBFE42A/UCO": {
      "address": "00006D18313F839B585A4AC2730F58DC065D122F223C4E3A28962883F17D02514A26",
      "lp_token_address": "0000774B49CAF598D83C1F32765B50D2DD4F3404E5357ABC126AE06E73AE66F061C3"
    },
    "0000E06BFF011D495E21EA9D5266435BBF2B5E721464132E4D24C404F51B0AFA8699/UCO": {
      "address": "0000D5BC05EC984F531E27E74E2804AB1DF1DD856B821D37F87D5AD9FDE9F4440966",
      "lp_token_address": "00004638E1D7397E8050826D1861194854F1105F568FCA616F99981507DAA5653EE7"
    },
    "0000E7367B119C45B5D92363E0E6C3E0067A6AD9E0B8C7CC7AB475AFFB010B24E380/UCO": {
      "address": "0000F92743735B9D8E7CCA5617D37F93B5E4A6036DABF1CDE8DB77CD0633B0D8671C",
      "lp_token_address": "000029C3AD030244EA5F0358D0F31D74E7DAE20DC9906ABED6C5775D5D73A1B2B4A6"
    }
  }
}
                  
Movements (0)

Ownerships (1)

  • Secret shared with 1 key

    Encoded secret

    B7A87E7286805F06997DF7D0952EB272FFA27DAB2F69E4909D6C4C86EACE510E79479EC30AB4176322C9C7DF9A6426513C36C4BC35AC7678738B1A6A

    Authorized keys

    • 00017877BCF4122095926A49489009649603AB129822A19EF9D573B8FD714911ED7F

Contract recipients (0)

Inputs (0)

Contract inputs (0)

Unspent outputs (1)

Proofs and signatures

Previous public key

0001FB5284811DAADEE31050E84A814A6015BB640F492D79B25135BBF43C4293D351

Previous signature

65B0119852625B00F1BFCE3F92CE884AD80C731BDFDB529C15975CC6ABD0D08EC6EAD32D7DFFF2D14052F67C17B8E24850BBF6054E9489F113BA80DEF2664304

Origin signature

30450220538E3B00FE253000D9E7AAE11A7A96FC6F4F7D1D9B264D9D5DC739F8FDBAC4B2022100B16D428804A2B3CA36512375AF672E09DDC6CF881FF5A561F65F9D4585B19580

Proof of work

01010484B78F4110D8E9D6FBEC72759895CC9D4532177314FBAA8B07BC525FC1AF48F150EFBF104B1819106B8E3563CD0E1FAAE5325F8FCFE58FF744C35F47669D2704

Proof of integrity

00C6FCE0C51F27EBC49738EAE64B93B0B32B721339ECCA67249335DFF39ACE5DB4

Coordinator signature

AB14AC8843B0A57DFCDE78084701696A53417ADD04CE79B52FD8817F00CB3A5079B8B29DE51D14BA7EBF472DD5C238D2EC4CA7F8241834E85D084E1F8159CF03

Validator #1 public key

000177BA744AC778DC2D51A1B7C622E7AC4BD1E1AA8DA2D0FCE71BAAB7DAD0E020E0

Validator #1 signature

EFFF2CA7A4EF33ABD56357FAAD9F340308347589148AFA2DABE520769F38C5E0F5B46D96151E1C778F9CD405703200281657B0A8304F198696217E5E10DBB50A

Validator #2 public key

00011B58ED42235461734EAF253BD97A80B92899ABCC3BE680D44B6825DD2A88A947

Validator #2 signature

4DA6B9307BCC8132B043B38717E2CCE79E366E8B57AED912F213C3FFF9307F41713B810F7F7983F83F0594357BF8B158784CC8B92DFCDB4DB537E478473E640F