Type
CONTRACT
Validation date
2025-01-09 16:05:24 UTC
Fee
0 UCO

Code (4.86 KB)

@version 1

condition triggered_by: transaction, on: deposit(level) do
now = Time.now() - Math.rem(Time.now(), 3600)

if transaction.timestamp >= 1848657600 do
  throw(message: "deposit impossible once farm is closed", code: 1001)
end

end_timestamp_from_level_or_throw(level, now)

if get_user_transfer_amount_or_throw() < 0.00000143 do
  throw(message: "deposit's minimum amount is 0.00000143", code: 1002)
end

true
end

actions triggered_by: transaction, on: deposit(level) do
now = Time.now() - Math.rem(Time.now(), 3600)
end_timestamp = end_timestamp_from_level_or_throw(level, now)
level = normalize_level(level, now)

start = nil

if level != "0" do
  start = now
end

transfer_amount = get_user_transfer_amount_or_throw()

user_genesis_address = get_user_genesis()

deposits = nil

if now > 1722513600 do
  res = calculate_new_rewards()
  deposits = res.deposits
  State.set("rewards_reserved", res.rewards_reserved)
  State.set("last_calculation_timestamp", res.last_calculation_timestamp)
  State.set("lp_tokens_deposited_by_level", res.lp_tokens_deposited_by_level)
else
  deposits = State.get("deposits", Map.new())
end

# ================================================
# MERGE DEPOSITS (same end)
# ================================================
user_deposits = Map.get(deposits, user_genesis_address, [])
same_deposit = nil

new_user_deposits = []

for user_deposit in user_deposits do
  if user_deposit.end == end_timestamp do
    same_deposit = user_deposit
  else
    new_user_deposits = List.prepend(new_user_deposits, user_deposit)
  end
end

new_deposit = nil

if same_deposit == nil do
  new_deposit = [
    amount: transfer_amount,
    reward_amount: 0,
    level: level,
    start: start,
    end: end_timestamp,
    id: String.from_number(Time.now())
  ]

  new_user_deposits = List.prepend(new_user_deposits, new_deposit)
else
  new_deposit = Map.set(same_deposit, "amount", same_deposit.amount + transfer_amount)
  new_user_deposits = List.prepend(new_user_deposits, new_deposit)
end

deposits = Map.set(deposits, user_genesis_address, new_user_deposits)
State.set("deposits", deposits)

lp_tokens_deposited = State.get("lp_tokens_deposited", 0)
State.set("lp_tokens_deposited", lp_tokens_deposited + transfer_amount)

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

lp_tokens_deposited_by_level =
  Map.set(
    lp_tokens_deposited_by_level,
    new_deposit.level,
    Map.get(lp_tokens_deposited_by_level, new_deposit.level, 0) + transfer_amount
  )

State.set("lp_tokens_deposited_by_level", lp_tokens_deposited_by_level)
end

condition triggered_by: transaction, on: claim(deposit_id) do
if transaction.timestamp <= 1722513600 do
  throw(message: "farm is not started yet", code: 2001)
end

user_genesis_address = get_user_genesis()

res = calculate_new_rewards()
user_deposit = get_user_deposit_or_throw(res.deposits, user_genesis_address, deposit_id)

if user_deposit.end > Time.now() do
  throw(message: "claiming before end of lock", code: 2002)
end

if user_deposit.reward_amount <= 0 do
  throw(message: "no reward to claim", code: 2003)
end

true
end

actions triggered_by: transaction, on: claim(deposit_id) do
user_genesis_address = get_user_genesis()

res = calculate_new_rewards()
State.set("last_calculation_timestamp", res.last_calculation_timestamp)
State.set("lp_tokens_deposited_by_level", res.lp_tokens_deposited_by_level)

user_deposit = get_user_deposit_or_throw(res.deposits, user_genesis_address, deposit_id)

if "UCO" == "UCO" do
  Contract.add_uco_transfer(to: transaction.address, amount: user_deposit.reward_amount)
else
  Contract.add_token_transfer(
    to: transaction.address,
    amount: user_deposit.reward_amount,
    token_address: "UCO"
  )
end

rewards_distributed = State.get("rewards_distributed", 0)
State.set("rewards_distributed", rewards_distributed + user_deposit.reward_amount)
State.set("rewards_reserved", res.rewards_reserved - user_deposit.reward_amount)

user_deposit = Map.set(user_deposit, "reward_amount", 0)
State.set("deposits", set_user_deposit(res.deposits, user_genesis_address, user_deposit))
end

condition triggered_by: transaction, on: withdraw(amount, deposit_id) do
user_genesis_address = get_user_genesis()

user_deposit =
  get_user_deposit_or_throw(State.get("deposits", Map.new()), user_genesis_address, deposit_id)

if amount > user_deposit.amount do
  throw(message: "amount requested is greater than amount deposited", code: 3001)
end

if user_deposit.end > Time.now() do
  throw(message: "withdrawing before end of lock", code: 3002)
end

true
end

actions triggered_by: transaction, on: withdraw(amount, deposit_id) do
user_genesis_address = get_user_genesis()

deposits = nil
rewards_reserved = nil

if Time.now() > 1722513600 do
  res = calculate_new_rewards()
  deposits = res.deposits
  rewards_reserved = res.rewards_reserved
  State.set("last_calculation_timestamp", res.last_calculation_timestamp)
  State.set("lp_tokens_deposited_by_level", res.lp_tokens_deposited_by_level)
else
  deposits = State.get("deposits", Map.new())
  rewards_reserved = State.get("rewards_reserved", 0)
end

user_deposit = get_user_deposit_or_throw(deposits, user_genesis_address, deposit_id)

if user_deposit.reward_amount > 0 do
  if "UCO" == "UCO" do
    Contract.add_uco_transfer(to: transaction.address, amount: user_deposit.reward_amount)
  else
    Contract.add_token_transfer(
      to: transaction.address,
      amount: user_deposit.reward_amount,
      token_address: "UCO"
    )
  end

  rewards_distributed = State.get("rewards_distributed", 0)
  State.set("rewards_distributed", rewards_distributed + user_deposit.reward_amount)

  rewards_reserved = rewards_reserved - user_deposit.reward_amount
end

State.set("rewards_reserved", rewards_reserved)

Contract.add_token_transfer(
  to: transaction.address,
  amount: amount,
  token_address: 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF
)

lp_tokens_deposited = State.get("lp_tokens_deposited", 0)
State.set("lp_tokens_deposited", lp_tokens_deposited - amount)

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

lp_tokens_deposited_by_level =
  Map.set(
    lp_tokens_deposited_by_level,
    user_deposit.level,
    Map.get(lp_tokens_deposited_by_level, user_deposit.level, 0) - amount
  )

State.set("lp_tokens_deposited_by_level", lp_tokens_deposited_by_level)

if amount == user_deposit.amount do
  deposits = remove_user_deposit(deposits, user_genesis_address, deposit_id)
else
  user_deposit = Map.set(user_deposit, "reward_amount", 0)
  user_deposit = Map.set(user_deposit, "amount", user_deposit.amount - amount)
  deposits = set_user_deposit(deposits, user_genesis_address, user_deposit)
end

State.set("deposits", deposits)
end

condition triggered_by: transaction, on: relock(level, deposit_id) do
now = Time.now() - Math.rem(Time.now(), 3600)

if transaction.timestamp >= 1848657600 do
  throw(message: "relock impossible once farm is closed", code: 4001)
end

end_timestamp = end_timestamp_from_level_or_throw(level, now)
level = normalize_level(level, now)

if level == "0" do
  throw(message: "can't relock to flexible", code: 4002)
end

user_genesis_address = get_user_genesis()

user_deposit =
  get_user_deposit_or_throw(State.get("deposits", Map.new()), user_genesis_address, deposit_id)

if level <= user_deposit.level do
  throw(message: "Relock's level must be greater than current level", code: 4003)
end

true
end

actions triggered_by: transaction, on: relock(level, deposit_id) do
now = Time.now() - Math.rem(Time.now(), 3600)
end_timestamp = end_timestamp_from_level_or_throw(level, now)
level = normalize_level(level, now)

user_genesis_address = get_user_genesis()

res = calculate_new_rewards()
State.set("last_calculation_timestamp", res.last_calculation_timestamp)

user_deposit = get_user_deposit_or_throw(res.deposits, user_genesis_address, deposit_id)

if user_deposit.reward_amount > 0 do
  if "UCO" == "UCO" do
    Contract.add_uco_transfer(to: transaction.address, amount: user_deposit.reward_amount)
  else
    Contract.add_token_transfer(
      to: transaction.address,
      amount: user_deposit.reward_amount,
      token_address: "UCO"
    )
  end
end

rewards_distributed = State.get("rewards_distributed", 0)
State.set("rewards_distributed", rewards_distributed + user_deposit.reward_amount)
State.set("rewards_reserved", res.rewards_reserved - user_deposit.reward_amount)

lp_tokens_deposited_by_level =
  Map.set(
    res.lp_tokens_deposited_by_level,
    user_deposit.level,
    Map.get(res.lp_tokens_deposited_by_level, user_deposit.level, 0) - user_deposit.amount
  )

lp_tokens_deposited_by_level =
  Map.set(
    lp_tokens_deposited_by_level,
    level,
    Map.get(lp_tokens_deposited_by_level, level, 0) + user_deposit.amount
  )

State.set("lp_tokens_deposited_by_level", lp_tokens_deposited_by_level)

user_deposit = Map.set(user_deposit, "reward_amount", 0)
user_deposit = Map.set(user_deposit, "start", now)
user_deposit = Map.set(user_deposit, "end", end_timestamp)
user_deposit = Map.set(user_deposit, "level", level)

State.set("deposits", set_user_deposit(res.deposits, user_genesis_address, user_deposit))
end

condition triggered_by: transaction, on: calculate_rewards() do
true
end

actions triggered_by: transaction, on: calculate_rewards() do
res = calculate_new_rewards()
State.set("last_calculation_timestamp", res.last_calculation_timestamp)
State.set("deposits", res.deposits)
State.set("rewards_reserved", res.rewards_reserved)
State.set("lp_tokens_deposited_by_level", res.lp_tokens_deposited_by_level)
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 = [
  0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF,
  1722513600,
  1848657600,
  "UCO",
  0x0000caf8d5baa374a2878fd87760a2a4ac9f5232dbb4f1143157a2006f95fff1b40e
]

new_code = Contract.call_function(0x000086E60124C986EBCAA5AFFB7A3DB8213072A132233FE61CF45651FDCF3C4CECEA, "get_farm_lock_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

fun get_user_transfer_amount_or_throw() do
transfers = Map.get(transaction.token_transfers, 0x0000caf8d5baa374a2878fd87760a2a4ac9f5232dbb4f1143157a2006f95fff1b40e, [])
transfer = List.at(transfers, 0)

if transfer == nil do
  throw(message: "no transfer found to the farm", code: 1003)
end

if transfer.token_address != 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF do
  throw(message: "invalid token transfered to the farm", code: 1004)
end

transfer.amount
end

fun calculate_new_rewards() do
rounded_now = Time.now() - Math.rem(Time.now(), 3600)

lp_tokens_deposited = State.get("lp_tokens_deposited", 0)
lp_tokens_deposited_by_level = State.get("lp_tokens_deposited_by_level", Map.new())
deposits = State.get("deposits", Map.new())
rewards_reserved = State.get("rewards_reserved", 0)
last_calculation_timestamp = State.get("last_calculation_timestamp", 1722513600)

if last_calculation_timestamp < rounded_now && last_calculation_timestamp < 1848657600 &&
     lp_tokens_deposited > 0 do
  duration_by_level = Map.new()
  duration_by_level = Map.set(duration_by_level, "0", 0)
  duration_by_level = Map.set(duration_by_level, "1", 7 * 86400)
  duration_by_level = Map.set(duration_by_level, "2", 30 * 86400)
  duration_by_level = Map.set(duration_by_level, "3", 90 * 86400)
  duration_by_level = Map.set(duration_by_level, "4", 180 * 86400)
  duration_by_level = Map.set(duration_by_level, "5", 365 * 86400)
  duration_by_level = Map.set(duration_by_level, "6", 730 * 86400)
  duration_by_level = Map.set(duration_by_level, "7", 1095 * 86400)

  weight_by_level = Map.new()
  weight_by_level = Map.set(weight_by_level, "0", 0)
  weight_by_level = Map.set(weight_by_level, "1", 0.013)
  weight_by_level = Map.set(weight_by_level, "2", 0.024)
  weight_by_level = Map.set(weight_by_level, "3", 0.043)
  weight_by_level = Map.set(weight_by_level, "4", 0.077)
  weight_by_level = Map.set(weight_by_level, "5", 0.139)
  weight_by_level = Map.set(weight_by_level, "6", 0.251)
  weight_by_level = Map.set(weight_by_level, "7", 0.453)

  rewards_allocated_at_each_year_end = Map.new()

  rewards_allocated_at_each_year_end =
    Map.set(rewards_allocated_at_each_year_end, "1", 45_000)

  rewards_allocated_at_each_year_end =
    Map.set(rewards_allocated_at_each_year_end, "2", 45_000 + 22_500)

  rewards_allocated_at_each_year_end =
    Map.set(
      rewards_allocated_at_each_year_end,
      "3",
      45_000 + 22_500 + 11_250
    )

  rewards_allocated_at_each_year_end =
    Map.set(
      rewards_allocated_at_each_year_end,
      "4",
      45_000 + 22_500 + 11_250 + 8_750
    )

  # remaining reward balance
  remaining_rewards_balance = 0

  if "UCO" == "UCO" do
    remaining_rewards_balance = contract.balance.uco
  else
    key = [token_address: "UCO", token_id: 0]
    remaining_rewards_balance = Map.get(contract.balance.tokens, key, 0)
  end

  # giveaways are distributed linearly over time
  time_elapsed_since_last_calc =
    rounded_now - State.get("last_calculation_timestamp", 1722513600)

  time_remaining_until_farm_end =
    1848657600 - State.get("last_calculation_timestamp", 1722513600)

  giveaways =
    remaining_rewards_balance + State.get("rewards_distributed", 0) -
      (45_000 + 22_500 + 11_250 + 8_750)

  giveaways_to_allocate =
    giveaways * (time_elapsed_since_last_calc / time_remaining_until_farm_end)

  # loop through all the hours since last calculation
  # period count is always minimum 1 because we ensure previously
  # rounded_now > last_calculation_timestamp
  periods_count =
    (rounded_now - State.get("last_calculation_timestamp", 1722513600)) / 3600

  last_calculation_timestamp = State.get("last_calculation_timestamp", 1722513600)

  for i in 1..periods_count do
    period_to = last_calculation_timestamp + 3600

    # find year / seconds remaining
    year = nil
    seconds_until_end_of_year = nil

    if last_calculation_timestamp < 1722513600 + 365 * 86400 do
      year = "1"

      seconds_until_end_of_year =
        1722513600 + 365 * 86400 - last_calculation_timestamp
    end

    if year == nil && last_calculation_timestamp < 1722513600 + 730 * 86400 do
      year = "2"

      seconds_until_end_of_year =
        1722513600 + 730 * 86400 - last_calculation_timestamp
    end

    if year == nil && last_calculation_timestamp < 1722513600 + 1095 * 86400 do
      year = "3"

      seconds_until_end_of_year =
        1722513600 + 1095 * 86400 - last_calculation_timestamp
    end

    if year == nil do
      year = "4"
      seconds_until_end_of_year = 1848657600 - last_calculation_timestamp
    end

    rewards_to_allocate = 0

    if period_to >= 1848657600 do
      rewards_to_allocate = remaining_rewards_balance - rewards_reserved
    else
      giveaway_for_period =
        giveaways_to_allocate *
          ((period_to - last_calculation_timestamp) / time_elapsed_since_last_calc)

      # calculate reward for this period
      rewards_to_allocate =
        (rewards_allocated_at_each_year_end[year] - State.get("rewards_distributed", 0) -
           rewards_reserved) *
          ((period_to - last_calculation_timestamp) / seconds_until_end_of_year) +
          giveaway_for_period
    end

    # calculate tokens_weighted for each level
    tokens_weighted_by_level = Map.new()

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "0",
        Map.get(lp_tokens_deposited_by_level, "0", 0) * weight_by_level["0"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "1",
        Map.get(lp_tokens_deposited_by_level, "1", 0) * weight_by_level["1"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "2",
        Map.get(lp_tokens_deposited_by_level, "2", 0) * weight_by_level["2"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "3",
        Map.get(lp_tokens_deposited_by_level, "3", 0) * weight_by_level["3"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "4",
        Map.get(lp_tokens_deposited_by_level, "4", 0) * weight_by_level["4"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "5",
        Map.get(lp_tokens_deposited_by_level, "5", 0) * weight_by_level["5"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "6",
        Map.get(lp_tokens_deposited_by_level, "6", 0) * weight_by_level["6"]
      )

    tokens_weighted_by_level =
      Map.set(
        tokens_weighted_by_level,
        "7",
        Map.get(lp_tokens_deposited_by_level, "7", 0) * weight_by_level["7"]
      )

    # calculate tokens weighted total
    tokens_weighted_total = 0

    for weighted_amount in Map.values(tokens_weighted_by_level) do
      tokens_weighted_total = tokens_weighted_total + weighted_amount
    end

    if tokens_weighted_total > 0 do
      # calculate rewards per level
      rewards_to_allocated_by_level = Map.new()

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "0",
          tokens_weighted_by_level["0"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "1",
          tokens_weighted_by_level["1"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "2",
          tokens_weighted_by_level["2"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "3",
          tokens_weighted_by_level["3"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "4",
          tokens_weighted_by_level["4"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "5",
          tokens_weighted_by_level["5"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "6",
          tokens_weighted_by_level["6"] / tokens_weighted_total * rewards_to_allocate
        )

      rewards_to_allocated_by_level =
        Map.set(
          rewards_to_allocated_by_level,
          "7",
          tokens_weighted_by_level["7"] / tokens_weighted_total * rewards_to_allocate
        )

      # update each deposit with the rewards
      updated_deposits = Map.new()

      for user_address in Map.keys(deposits) do
        user_deposits = deposits[user_address]
        updated_user_deposits = []

        for user_deposit in user_deposits do
          if user_deposit.level != "0" do
            # calc rewards
            user_deposit =
              Map.set(
                user_deposit,
                "reward_amount",
                user_deposit.reward_amount +
                  user_deposit.amount * weight_by_level[user_deposit.level] /
                    tokens_weighted_by_level[user_deposit.level] *
                    rewards_to_allocated_by_level[user_deposit.level]
              )

            # on level change, update cursors and deposit
            previous_level = String.from_number(String.to_number(user_deposit.level) - 1)

            if user_deposit.end - duration_by_level[previous_level] <= period_to do
              lp_tokens_deposited_by_level =
                Map.set(
                  lp_tokens_deposited_by_level,
                  user_deposit.level,
                  Map.get(lp_tokens_deposited_by_level, user_deposit.level, 0) -
                    user_deposit.amount
                )

              lp_tokens_deposited_by_level =
                Map.set(
                  lp_tokens_deposited_by_level,
                  previous_level,
                  Map.get(lp_tokens_deposited_by_level, previous_level, 0) + user_deposit.amount
                )

              user_deposit = Map.set(user_deposit, "level", previous_level)

              if previous_level == "0" do
                user_deposit = Map.set(user_deposit, "start", nil)
                user_deposit = Map.set(user_deposit, "end", 0)
              end
            end
          end

          updated_user_deposits = List.prepend(updated_user_deposits, user_deposit)
        end

        updated_deposits = Map.set(updated_deposits, user_address, updated_user_deposits)
      end

      deposits = updated_deposits
      rewards_reserved = rewards_reserved + rewards_to_allocate
      last_calculation_timestamp = period_to
    end
  end
else
  # edge case when lp_tokens_deposited = 0
  if last_calculation_timestamp < rounded_now && last_calculation_timestamp < 1848657600 do
    last_calculation_timestamp = rounded_now
  end
end

[
  deposits: deposits,
  rewards_reserved: rewards_reserved,
  last_calculation_timestamp: last_calculation_timestamp,
  lp_tokens_deposited_by_level: lp_tokens_deposited_by_level
]
end

export fun(get_farm_infos()) do
now = Time.now() - Math.rem(Time.now(), 3600)

reward_year1 = 0
reward_year2 = 0
reward_year3 = 0
reward_year4 = 0

if now < 1722513600 + 365 * 86400 - 1 do
  reward_year1 =
    45_000 - State.get("rewards_reserved", 0) - State.get("rewards_distributed", 0)

  reward_year2 = 22_500
  reward_year3 = 11_250
  reward_year4 = 8_750
end

if reward_year1 == 0 && now < 1722513600 + 730 * 86400 - 1 do
  reward_year2 =
    45_000 + 22_500 - State.get("rewards_reserved", 0) -
      State.get("rewards_distributed", 0)

  reward_year3 = 11_250
  reward_year4 = 8_750
end

if reward_year2 == 0 && now < 1722513600 + 1095 * 86400 - 1 do
  reward_year3 =
    45_000 + 22_500 + 11_250 - State.get("rewards_reserved", 0) -
      State.get("rewards_distributed", 0)

  reward_year4 = 8_750
end

if reward_year3 == 0 && now < 1848657600 do
  reward_year4 =
    45_000 + 22_500 + 11_250 + 8_750 -
      State.get("rewards_reserved", 0) - State.get("rewards_distributed", 0)
end

years = [
  [
    year: 1,
    start: 1722513600,
    end: 1722513600 + 365 * 86400 - 1,
    rewards: reward_year1
  ],
  [
    year: 2,
    start: 1722513600 + 365 * 86400,
    end: 1722513600 + 730 * 86400 - 1,
    rewards: reward_year2
  ],
  [
    year: 3,
    start: 1722513600 + 730 * 86400,
    end: 1722513600 + 1095 * 86400 - 1,
    rewards: reward_year3
  ],
  [
    year: 4,
    start: 1722513600 + 1095 * 86400,
    end: 1848657600,
    rewards: reward_year4
  ]
]

reward_token_balance = nil

if "UCO" == "UCO" do
  reward_token_balance = contract.balance.uco
else
  key = [token_address: "UCO", token_id: 0]
  reward_token_balance = Map.get(contract.balance.tokens, key, 0)
end

weight_by_level = Map.new()
weight_by_level = Map.set(weight_by_level, "0", 0)
weight_by_level = Map.set(weight_by_level, "1", 0.013)
weight_by_level = Map.set(weight_by_level, "2", 0.024)
weight_by_level = Map.set(weight_by_level, "3", 0.043)
weight_by_level = Map.set(weight_by_level, "4", 0.077)
weight_by_level = Map.set(weight_by_level, "5", 0.139)
weight_by_level = Map.set(weight_by_level, "6", 0.251)
weight_by_level = Map.set(weight_by_level, "7", 0.453)

available_levels = Map.new()
available_levels = Map.set(available_levels, "0", now + 0)
available_levels = Map.set(available_levels, "1", now + 7 * 86400)
available_levels = Map.set(available_levels, "2", now + 30 * 86400)
available_levels = Map.set(available_levels, "3", now + 90 * 86400)
available_levels = Map.set(available_levels, "4", now + 180 * 86400)
available_levels = Map.set(available_levels, "5", now + 365 * 86400)
available_levels = Map.set(available_levels, "6", now + 730 * 86400)
available_levels = Map.set(available_levels, "7", now + 1095 * 86400)

filtered_levels = Map.new()

end_reached = false

for level in Map.keys(available_levels) do
  start_level = Map.get(available_levels, level)

  if start_level < 1848657600 do
    filtered_levels = Map.set(filtered_levels, level, start_level)
  else
    if !end_reached && Map.size(filtered_levels) > 0 do
      filtered_levels = Map.set(filtered_levels, level, 1848657600)
      end_reached = true
    end
  end
end

lp_tokens_deposited_by_level = State.get("lp_tokens_deposited_by_level", Map.new())
lp_tokens_deposited_weighted = 0

for level in Map.keys(lp_tokens_deposited_by_level) do
  lp_tokens_deposited_weighted =
    lp_tokens_deposited_weighted +
      lp_tokens_deposited_by_level[level] * weight_by_level[level]
end

deposits_count_by_level = Map.new()

for user_deposits in Map.values(State.get("deposits", Map.new())) do
  for user_deposit in user_deposits do
    deposits_count_by_level =
      Map.set(
        deposits_count_by_level,
        user_deposit.level,
        Map.get(deposits_count_by_level, user_deposit.level, 0) + 1
      )
  end
end

stats = Map.new()

for level in Map.keys(available_levels) do
  remaining_rewards = []

  for y in years do
    rewards = 0

    if lp_tokens_deposited_weighted > 0 do
      rewards =
        Map.get(lp_tokens_deposited_by_level, level, 0) * weight_by_level[level] /
          lp_tokens_deposited_weighted * y.rewards
    end

    remaining_rewards =
      List.append(remaining_rewards, start: y.start, end: y.end, remaining_rewards: rewards)
  end

  stats =
    Map.set(stats, level,
      weight: weight_by_level[level],
      lp_tokens_deposited: Map.get(lp_tokens_deposited_by_level, level, 0),
      deposits_count: Map.get(deposits_count_by_level, level, 0),
      remaining_rewards: remaining_rewards
    )
end

[
  lp_token_address: 0x00006394EF24DFDC6FDFC3642FDC83827591A485704BB997221C0B9F313A468BDEAF,
  reward_token: "UCO",
  start_date: 1722513600,
  end_date: 1848657600,
  lp_tokens_deposited: State.get("lp_tokens_deposited", 0),
  remaining_rewards: reward_token_balance - State.get("rewards_reserved", 0),
  rewards_distributed: State.get("rewards_distributed", 0),
  available_levels: filtered_levels,
  stats: stats
]
end

export fun(get_user_infos(user_genesis_address)) do
reply = []

for user_deposit in Map.get(
      State.get("deposits", Map.new()),
      String.to_hex(user_genesis_address),
      []
    ) do
  info = [
    id: user_deposit.id,
    amount: user_deposit.amount,
    reward_amount: user_deposit.reward_amount,
    level: user_deposit.level
  ]

  if user_deposit.end > Time.now() do
    info = Map.set(info, "end", user_deposit.end)
    info = Map.set(info, "start", user_deposit.start)
  end

  reply = List.append(reply, info)
end

reply
end

fun get_user_genesis() do
Chain.get_genesis_address(Chain.get_previous_address(transaction))
end

fun get_user_deposit_or_throw(deposits, user_genesis_address, deposit_id) do
reply = nil

for user_deposit in Map.get(deposits, user_genesis_address, []) do
  if user_deposit.id == deposit_id do
    reply = user_deposit
  end
end

if reply == nil do
  throw(message: "deposit not found", code: 6004)
end

reply
end

fun set_user_deposit(deposits, user_genesis_address, deposit) do
updated_user_deposits = []

for user_deposit in Map.get(deposits, user_genesis_address, []) do
  if user_deposit.id == deposit.id do
    updated_user_deposits = List.prepend(updated_user_deposits, deposit)
  else
    updated_user_deposits = List.prepend(updated_user_deposits, user_deposit)
  end
end

Map.set(deposits, user_genesis_address, updated_user_deposits)
end

fun remove_user_deposit(deposits, user_genesis_address, deposit_id) do
updated_user_deposits = []

for user_deposit in Map.get(deposits, user_genesis_address, []) do
  if user_deposit.id != deposit_id do
    updated_user_deposits = List.prepend(updated_user_deposits, user_deposit)
  end
end

if List.size(updated_user_deposits) == 0 do
  Map.delete(deposits, user_genesis_address)
else
  Map.set(deposits, user_genesis_address, updated_user_deposits)
end
end

fun end_timestamp_from_level_or_throw(level, rounded_now) do
end_timestamp = nil

if !List.in?(["max", "flex", "0", "1", "2", "3", "4", "5", "6", "7"], level) do
  throw(message: "invalid level", code: 6000)
end

if level == "max" do
  if 1848657600 - rounded_now < 3 * 365 * 86400 do
    end_timestamp = 1848657600
  else
    throw(message: "max only available when less than 3 years remaining", code: 6001)
  end
else
  if List.in?(["flex", "0"], level) do
    end_timestamp = 0
  else
    duration_by_level = Map.new()
    duration_by_level = Map.set(duration_by_level, "1", 7 * 86400)
    duration_by_level = Map.set(duration_by_level, "2", 30 * 86400)
    duration_by_level = Map.set(duration_by_level, "3", 90 * 86400)
    duration_by_level = Map.set(duration_by_level, "4", 180 * 86400)
    duration_by_level = Map.set(duration_by_level, "5", 365 * 86400)
    duration_by_level = Map.set(duration_by_level, "6", 730 * 86400)
    duration_by_level = Map.set(duration_by_level, "7", 1095 * 86400)

    end_timestamp = rounded_now + duration_by_level[level]

    if end_timestamp > 1848657600 do
      throw(message: "lock's end cannot be greater than farm's end", code: 6002)
    end

    if end_timestamp <= 1722513600 do
      throw(message: "lock's end cannot be lesser than farm's start", code: 6003)
    end
  end
end

end_timestamp
end

fun normalize_level(level, rounded_now) do
normalized_level = nil

if List.in?(["0", "1", "2", "3", "4", "5", "6", "7"], level) do
  normalized_level = level
end

if level == "flex" do
  normalized_level = "0"
end

if level == "max" do
  duration_by_level = Map.new()
  duration_by_level = Map.set(duration_by_level, "0", 0)
  duration_by_level = Map.set(duration_by_level, "1", 7 * 86400)
  duration_by_level = Map.set(duration_by_level, "2", 30 * 86400)
  duration_by_level = Map.set(duration_by_level, "3", 90 * 86400)
  duration_by_level = Map.set(duration_by_level, "4", 180 * 86400)
  duration_by_level = Map.set(duration_by_level, "5", 365 * 86400)
  duration_by_level = Map.set(duration_by_level, "6", 730 * 86400)
  duration_by_level = Map.set(duration_by_level, "7", 1095 * 86400)

  for l in Map.keys(duration_by_level) do
    if normalize_level == nil && end_timestamp <= rounded_now + duration_by_level[l] do
      normalize_level = l
    end
  end
end

normalized_level
end

Content (0 B)

State (2.55 KB)

{
  "deposits": {
    "00000BC0EBA2DBCE4455B46F5E51AFAABA6EB4C7FBA1D4E2E6DABD55DC70F9A04D6F": [
      {
        "amount": 1.1111,
        "end": 1759932000,
        "id": "1728395950",
        "level": "5",
        "reward_amount": 266.93264497,
        "start": 1728396000
      },
      {
        "amount": 13.4101426,
        "end": 1821873600,
        "id": "1727265978",
        "level": "7",
        "reward_amount": 12213.86517116,
        "start": 1727265600
      },
      {
        "amount": 0.4,
        "end": 0,
        "id": "1727091755",
        "level": "0",
        "reward_amount": 0,
        "start": null
      },
      {
        "amount": 1.0,
        "end": 0,
        "id": "1726999778",
        "level": "0",
        "reward_amount": 0,
        "start": null
      },
      {
        "amount": 1.0e-5,
        "end": 1821985200,
        "id": "1725552233",
        "level": "7",
        "reward_amount": 0.00894936,
        "start": 1727377200
      },
      {
        "amount": 1.0,
        "end": 0,
        "id": "1725552158",
        "level": "0",
        "reward_amount": 0,
        "start": null
      },
      {
        "amount": 1.0,
        "end": 0,
        "id": "1726050537",
        "level": "0",
        "reward_amount": 60.9334791,
        "start": null
      },
      {
        "amount": 2.0,
        "end": 0,
        "id": "1726831636",
        "level": "0",
        "reward_amount": 0,
        "start": null
      },
      {
        "amount": 2.0e-5,
        "end": 1821884400,
        "id": "1727276614",
        "level": "7",
        "reward_amount": 0.01815616,
        "start": 1727276400
      },
      {
        "amount": 0.502,
        "end": 0,
        "id": "1727380180",
        "level": "0",
        "reward_amount": 0.98476243,
        "start": null
      },
      {
        "amount": 0.3,
        "end": 0,
        "id": "1727602145",
        "level": "0",
        "reward_amount": 0,
        "start": null
      },
      {
        "amount": 0.0001,
        "end": 0,
        "id": "1727726349",
        "level": "0",
        "reward_amount": 1.9523e-4,
        "start": null
      },
      {
        "amount": 2.5e-5,
        "end": 0,
        "id": "1727727077",
        "level": "0",
        "reward_amount": 0,
        "start": null
      },
      {
        "amount": 0.5,
        "end": 1822986000,
        "id": "1728380308",
        "level": "7",
        "reward_amount": 392.46020238,
        "start": 1728378000
      },
      {
        "amount": 1.0,
        "end": 1823032800,
        "id": "1728428112",
        "level": "7",
        "reward_amount": 779.86015934,
        "start": 1728424800
      },
      {
        "amount": 1.0,
        "end": 0,
        "id": "1728464687",
        "level": "0",
        "reward_amount": 11.68747044,
        "start": null
      },
      {
        "amount": 0.11134,
        "end": 0,
        "id": "1728377593",
        "level": "0",
        "reward_amount": 0.18280236,
        "start": null
      },
      {
        "amount": 2.234,
        "end": 0,
        "id": "1729523324",
        "level": "0",
        "reward_amount": 3.84818295,
        "start": null
      },
      {
        "amount": 2.66666,
        "end": 0,
        "id": "1734455092",
        "level": "0",
        "reward_amount": 4.59346284,
        "start": null
      },
      {
        "amount": 0.0001,
        "end": 1737046800,
        "id": "1734455674",
        "level": "2",
        "reward_amount": 0.00102082,
        "start": 1734454800
      }
    ],
    "0000162D8384E5DCE6656E10A658CB749A901DDA233D173146F2CDE297046DA83006": [
      {
        "amount": 0.20420297,
        "end": 0,
        "id": "1729427333",
        "level": "0",
        "reward_amount": 0.33507149,
        "start": null
      }
    ],
    "00006AFF130BEB6BE9B02B80FFC13DB5EABFB0A7D167BAFC9F2DF8F141D7755FB39F": [
      {
        "amount": 17.97108234,
        "end": 1738087200,
        "id": "1724890822",
        "level": "2",
        "reward_amount": 85.20976298,
        "start": 1735495200
      }
    ],
    "0000AF119B8D021DF8683CC438DB0EBA154589F34FE3F897FB00888A16177C1F44C9": [
      {
        "amount": 2.00661538,
        "end": 0,
        "id": "1728451071",
        "level": "0",
        "reward_amount": 119.94322043,
        "start": null
      }
    ]
  },
  "last_calculation_timestamp": 1736438400,
  "lp_tokens_deposited": 48.75074829,
  "lp_tokens_deposited_by_level": {
    "0": 14.42494335,
    "1": 0.33335,
    "2": 17.97118234,
    "3": 0.0,
    "4": 0.0,
    "5": 1.1111,
    "6": 0.0,
    "7": 14.9101726
  },
  "rewards_distributed": 3874.48454685,
  "rewards_reserved": 13947.31657239
}
                  
Movements (0)

Ownerships (1)

  • Secret shared with 1 key

    Encoded secret

    B8DE231166ACF3C58296E797BFA7C55D314049163E181D49AC87284A5F93649F43786659A9208D7983EBBF1137EC159C869A1F0A5E58A1A81EFD79D2

    Authorized keys

    • 00017877BCF4122095926A49489009649603AB129822A19EF9D573B8FD714911ED7F

Contract recipients (0)

Inputs (0)

Contract inputs (0)

Unspent outputs (0)

Proofs and signatures

Previous public key

00018A7B93A34EEAB4811F95C6C9D81FB04090EBB03AB4F18BE58885E24DD4DE39F7

Previous signature

25C817932F2EB405E4A93FA6D5A6E81E4506ADA426F19DD6676CBA298864DB19044034CEA13451A2A5BBB625120C6CFC39D01FD157C277615BB9440826CCEA08

Origin signature

304402203F0B2738CB241E53C6697850C9390CF5503FB01D1BEEF52F93BEF7FAEE749F4E02200A160DEACE757D6E8B1F07988230B361A6F769F70473E35EC0BC4D9DD70DA67B

Proof of work

010104AB672F1E69B064D192819F1797C1926F158DBA8F3924AC732B4C4D70D0C8EA0A0D6506E5896C9C2524D2BE26CB5016287E1816A597C408008BA36FCB154A7765

Proof of integrity

005612C5DD5D1E54B34B0279A5378C3FC3D2A0244CE9F1F15FF2F527ACD5F75DBF

Coordinator signature

E6CF5E1F338D98044AD9785586A4BC8FF960DAF72BBA179A4B10D1D515BEAC34A914A8E3AAFE6559E6BA083EC0E7B1A4E872D85E18FCFFE97C7217D9360D800F

Validator #1 public key

0001923076BC39A300949685070A2979143FFD0CFDF5BE286915C8D0CE0FE2117B8F

Validator #1 signature

1E230E8DE656DA170329DE67CDC167AABBEB8F76E324C48B14E3008585E10A71F0A2EC45176FEEF03261B08F69099EACF253DC69DF118C2398892907F2E7010C

Validator #2 public key

0001A5E6F6D02CE7E311CF3CC87C79329877BC7E086C52A92FDED417D6F7D43F13C5

Validator #2 signature

0653B95DD1E5F32925DC894C78809F56AD8A95ABA78270B91958C9EE0A84E3631F520A2D70A51B7350E0ED7B9621DC80CB77020B696754360A81FA831BE1480E