Type
CONTRACT
Validation date
2024-09-18 18:05:06 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 (719 B)

 
{
  "deposits": {
    "00000BC0EBA2DBCE4455B46F5E51AFAABA6EB4C7FBA1D4E2E6DABD55DC70F9A04D6F": [
      {
        "amount": 1.0e-5,
        "end": 1757088000,
        "id": "1725552233",
        "level": "5",
        "reward_amount": 0.13518925,
        "start": 1725552000
      },
      {
        "amount": 1.0,
        "end": 0,
        "id": "1725552158",
        "level": "0",
        "reward_amount": 913.99563398,
        "start": null
      },
      {
        "amount": 1.0,
        "end": 1728640800,
        "id": "1726050537",
        "level": "2",
        "reward_amount": 919.13465118,
        "start": 1726048800
      }
    ],
    "00006AFF130BEB6BE9B02B80FFC13DB5EABFB0A7D167BAFC9F2DF8F141D7755FB39F": [
      {
        "amount": 17.97108234,
        "end": 0,
        "id": "1724890822",
        "level": "0",
        "reward_amount": 933.29617689,
        "start": null
      }
    ]
  },
  "last_calculation_timestamp": 1726682400,
  "lp_tokens_deposited": 19.97109234,
  "lp_tokens_deposited_by_level": {
    "0": 18.97108234,
    "1": 0.0,
    "2": 1.0,
    "5": 1.0e-5
  },
  "rewards_distributed": 0,
  "rewards_reserved": 2766.56167198
}
                  
Movements (0)

Ownerships (1)

  • Secret shared with 1 key

    Encoded secret

    3D670A8E0AC78D6F0B666A5BB2738EEE688A2062816E7E3052E5C633BF5B98E5E322F716BDE7373020B2BA7D39A1042C7018F7C9F6E0EF15F048D10E

    Authorized keys

    • 00017877BCF4122095926A49489009649603AB129822A19EF9D573B8FD714911ED7F

Contract recipients (0)

Inputs (0)

Contract inputs (0)

Unspent outputs (0)

Proofs and signatures

Previous public key

00011B28D08DC2819A5980F40574DC9CF0A05356F382928271BC0A6C05B0EF63B2B1

Previous signature

72E1D7354D7A562E406D5E188C5FFBB99EBC03FB02228840AFA37BC5C55FF5D0538C438AEE3909048FB4A184499F100DAC7A64C05E30B8A71DA1C3172EEC1E02

Origin signature

3044022011DF3D8CF9E586BA0309FB752329A462042E6BEA54BD3C5E11E0EFB4CCA8C18D02206DA7C5D8B894FAEAC4EA07C52A63497BC6C99E62B35305977A6EDAB22E5EA81B

Proof of work

0101046C39D56B717142B6EE14B0F8B2561ECA458F3D2D12C9977D613F78829419063211F9C21F7BB0D56B6523040A8156BE22B6E9D6332B88ED882574D12AE32F7A45

Proof of integrity

00EAEA178BCBBB77F952F74FFAC2984C2BEB6AC43AFE3BA34C94066076FCA1CDA6

Coordinator signature

8DBA0EF5012579BF15335E6E3277BAE31AFD7D7A97B5D82F113F233E382A0FB333930844385800080ECDDD6282AA3BF3BCE3C06835FC08A4E083491BD03CD702

Validator #1 public key

0001923076BC39A300949685070A2979143FFD0CFDF5BE286915C8D0CE0FE2117B8F

Validator #1 signature

522EAE03C90E7584AF06025176A6387ADF2A1DCCA944FFF8E1356EC2C34B3555168ABCD9A1D938CF16B17F83451990F32FE316273585EF9C0C1ED266095E490B

Validator #2 public key

000109F3F0A3EA1C4E40F676D27DF717E0A0C76D4A9EC89A8CAD79DFD414C78C1CD2

Validator #2 signature

951A2B91E207B82C06BE5FA939BB630F4F753B53C3E67589EE3DF6F1C71E9A76EEFE46D760EDD3CC1419FD2DD989F5F2F3F6ED33588D3EE9347FBFCFC74DF80B