Type
TRANSFER
Validation date
2025-02-03 10:25:20 UTC
Fee
0 UCO

Code (3.51 KB)

@version 1

condition triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount), as: [
token_transfers: (
user_amounts = get_user_transfers_amount(transaction)

valid_transfers? = user_amounts.token1 > 0 && user_amounts.token2 > 0
valid_min? = user_amounts.token1 >= token1_min_amount && user_amounts.token2 >= token2_min_amount

valid_transfers? && valid_min?
)
]

actions triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount) do
pool_balances = get_pool_balances()
user_amounts = get_user_transfers_amount(transaction)

lp_token_supply = State.get("lp_token_supply", 0)
reserves = State.get("reserves", [token1: 0, token2: 0])

final_amounts = get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount)
token1_to_refund = user_amounts.token1 - final_amounts.token1
token2_to_refund = user_amounts.token2 - final_amounts.token2

token1_amount = user_amounts.token1 + pool_balances.token1 - reserves.token1 - token1_to_refund
token2_amount = user_amounts.token2 + pool_balances.token2 - reserves.token2 - token2_to_refund

lp_token_to_mint = get_lp_token_to_mint(token1_amount, token2_amount)

# Handle invalid values and refund user 
valid_amounts? = final_amounts.token1 > 0 && final_amounts.token2 > 0
valid_liquidity? = lp_token_to_mint > 0

if valid_amounts? && valid_liquidity? do
lp_token_to_mint_bigint = Math.trunc(lp_token_to_mint * 100_000_000)

# Remove minimum liquidity if this is the first liquidity if the pool
# First liquidity minted and burned on pool creation
if lp_token_supply == 0 do
  lp_token_to_mint_bigint = lp_token_to_mint_bigint - 10
end

token_specification = [
  aeip: [8, 18, 19],
  supply: lp_token_to_mint_bigint,
  token_reference: 0x00000D299B994C7325649A329D40617644979C6E5085B880575375441F4EC6366112,
  recipients: [
    [to: transaction.address, amount: lp_token_to_mint_bigint]
  ]
]

new_token1_reserve = user_amounts.token1 + pool_balances.token1 - token1_to_refund
new_token2_reserve = user_amounts.token2 + pool_balances.token2 - token2_to_refund

State.set("lp_token_supply", lp_token_supply + lp_token_to_mint)
State.set("reserves", [token1: new_token1_reserve, token2: new_token2_reserve])

if token1_to_refund > 0 do
  Contract.add_token_transfer(to: transaction.address, amount: token1_to_refund, token_address: "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A")
end

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

Contract.set_type("token")
Contract.set_content(Json.to_string(token_specification))
else
# Liquidity provision is invalid, refund user of it's tokens
Contract.set_type("transfer")

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

Contract.add_token_transfer(to: transaction.address, amount: user_amounts.token1, token_address: "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A")
end
end

condition triggered_by: transaction, on: remove_liquidity(), as: [
token_transfers: (
user_amount = get_user_lp_amount(transaction.token_transfers)

user_amount > 0
)
]

actions triggered_by: transaction, on: remove_liquidity() do
return? = true

user_amount = get_user_lp_amount(transaction.token_transfers)
lp_token_supply = State.get("lp_token_supply", 0)

if lp_token_supply > 0 do
pool_balances = get_pool_balances()

token1_to_remove = (user_amount * pool_balances.token1) / lp_token_supply
token2_to_remove = (user_amount * pool_balances.token2) / lp_token_supply

if token1_to_remove > 0 && token2_to_remove > 0 do
  return? = false

  new_token1_reserve = pool_balances.token1 - token1_to_remove
  new_token2_reserve = pool_balances.token2 - token2_to_remove

  State.set("lp_token_supply", lp_token_supply - user_amount)
  State.set("reserves", [token1: new_token1_reserve, token2: new_token2_reserve])

  Contract.set_type("transfer")
  Contract.add_token_transfer(to: transaction.address, amount: token1_to_remove, token_address: "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A")
  if "UCO" == "UCO" do
    Contract.add_uco_transfer(to: transaction.address, amount: token2_to_remove)
  else
    Contract.add_token_transfer(to: transaction.address, amount: token2_to_remove, token_address: "UCO")
  end
end
end

if return? do
# Refund is invalid, return LP tokens to user
Contract.set_type("transfer")
Contract.add_token_transfer(to: transaction.address, amount: user_amount, token_address: 0x00000D299B994C7325649A329D40617644979C6E5085B880575375441F4EC6366112)
end
end

condition triggered_by: transaction, on: swap(_min_to_receive), as: [
token_transfers: (
transfer = get_user_transfer(transaction)

transfer != nil
)
]

actions triggered_by: transaction, on: swap(min_to_receive) do
transfer = get_user_transfer(transaction)

swap = get_output_swap_infos(transfer.token_address, transfer.amount)

if swap.output_amount > 0 && swap.output_amount >= min_to_receive do

pool_balances = get_pool_balances()
token_to_send = nil
token1_volume = 0
token2_volume = 0
token1_fee = 0
token2_fee = 0
token1_protocol_fee = 0
token2_protocol_fee = 0
if transfer.token_address == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" do
  pool_balances = [
    token1: pool_balances.token1 + transfer.amount - swap.protocol_fee,
    token2: pool_balances.token2 - swap.output_amount
  ]
  token_to_send = "UCO"
  token1_volume = transfer.amount
  token1_fee = swap.fee
  token1_protocol_fee = swap.protocol_fee
else
  pool_balances = [
    token1: pool_balances.token1 - swap.output_amount,
    token2: pool_balances.token2 + transfer.amount - swap.protocol_fee
  ]
  token_to_send = "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A"
  token2_volume = transfer.amount
  token2_fee = swap.fee
  token2_protocol_fee = swap.protocol_fee
end

State.set("reserves", [token1: pool_balances.token1, token2: pool_balances.token2])

stats = State.get("stats", [
  token1_total_fee: 0,
  token2_total_fee: 0,
  token1_total_volume: 0,
  token2_total_volume: 0,
  token1_total_protocol_fee: 0,
  token2_total_protocol_fee: 0,
])

token1_total_fee = Map.get(stats, "token1_total_fee") + token1_fee
token2_total_fee = Map.get(stats, "token2_total_fee") + token2_fee
token1_total_volume = Map.get(stats, "token1_total_volume") + token1_volume
token2_total_volume = Map.get(stats, "token2_total_volume") + token2_volume
token1_total_protocol_fee = Map.get(stats, "token1_total_protocol_fee") + token1_protocol_fee
token2_total_protocol_fee = Map.get(stats, "token2_total_protocol_fee") + token2_protocol_fee

stats = Map.set(stats, "token1_total_fee", token1_total_fee)
stats = Map.set(stats, "token2_total_fee", token2_total_fee)
stats = Map.set(stats, "token1_total_volume", token1_total_volume)
stats = Map.set(stats, "token2_total_volume", token2_total_volume)
stats = Map.set(stats, "token1_total_protocol_fee", token1_total_protocol_fee)
stats = Map.set(stats, "token2_total_protocol_fee", token2_total_protocol_fee)

State.set("stats", stats)

Contract.set_type("transfer")
if token_to_send == "UCO" do
  Contract.add_uco_transfer(to: transaction.address, amount: swap.output_amount)
else
  Contract.add_token_transfer(to: transaction.address, amount: swap.output_amount, token_address: token_to_send)
end

if swap.protocol_fee > 0 do
  if transfer.token_address == "UCO" do
    Contract.add_uco_transfer(to: 0x0000CC1FADBD31B043947C016E09CCD59BC3C81E55AB8A4932A046236D5E0FEE9E45, amount: swap.protocol_fee)
  else
    Contract.add_token_transfer(to: 0x0000CC1FADBD31B043947C016E09CCD59BC3C81E55AB8A4932A046236D5E0FEE9E45, amount: swap.protocol_fee, token_address: transfer.token_address)
  end
end
else
# Swap is invalid, return tokens to user
Contract.set_type("transfer")

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

condition triggered_by: transaction, on: update_code(), as: [
previous_public_key: (
# Pool code can only be updated from the router contract of the dex

# Transaction is not yet validated so we need to use previous address
# to get the genesis address
previous_address = Chain.get_previous_address()
Chain.get_genesis_address(previous_address) == 0x000077CEC9D9DBC0183CAF843CBB4828A932BB1457E382AC83B31AD6F9755DD50FFC
)
]

actions triggered_by: transaction, on: update_code() do
params = [
"00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A",
"UCO",
0x0000AF33F129F682ED08B1423B1C9E555AFBF9325A0D0695A63726E192BC96BEDFA3,
0x00000D299B994C7325649A329D40617644979C6E5085B880575375441F4EC6366112
]

new_code = Contract.call_function(0x00004CE47B2828E923EB679FEF311DD458AA0571C67DB5CB46B4E0793CAC525AC791, "get_pool_code", params)

if Code.is_valid?(new_code) do
Contract.set_type("contract")
Contract.set_code(new_code)
end
end

condition triggered_by: transaction, on: set_protocol_fee(new_protocol_fee), as: [
content: new_protocol_fee <= 1 && new_protocol_fee >= 0,
previous_public_key: (
previous_address = Chain.get_previous_address()
Chain.get_genesis_address(previous_address) == 0x0000BE4D33FC48CD4791A58EF7296F6916F5A2032A4E66111CF10521D08FC660A4D3
)
]

actions triggered_by: transaction, on: set_protocol_fee(new_protocol_fee) do
State.set("protocol_fee", new_protocol_fee)
end

condition triggered_by: transaction, on: set_lp_fee(new_lp_fee), as: [
content: new_lp_fee <= 1 && new_lp_fee >= 0,
previous_public_key: (
previous_address = Chain.get_previous_address()
Chain.get_genesis_address(previous_address) == 0x0000BE4D33FC48CD4791A58EF7296F6916F5A2032A4E66111CF10521D08FC660A4D3
)
]

actions triggered_by: transaction, on: set_lp_fee(new_lp_fee) do
State.set("lp_fee", new_lp_fee)
end

export fun get_ratio(token_address) do
reserves = State.get("reserves", [token1: 0, token2: 0])
ratio = 0

token_address = String.to_uppercase(token_address)

if reserves.token1 > 0 && reserves.token2 > 0 do
if token_address == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" 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 == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" do
  ratio = reserves.token2 / reserves.token1
else
  ratio = reserves.token1 / reserves.token2
end
end

amount * ratio
end

export fun get_lp_token_to_mint(token1_amount, token2_amount) do
lp_token_supply = State.get("lp_token_supply", 0)
reserves = State.get("reserves", [token1: 0, token2: 0])

if lp_token_supply == 0 || reserves.token1 == 0 || reserves.token2 == 0 do
# First liquidity
Math.sqrt(token1_amount * token2_amount)
else
mint_amount1 = (token1_amount * lp_token_supply) / reserves.token1
mint_amount2 = (token2_amount * lp_token_supply) / reserves.token2

if mint_amount1 < mint_amount2 do
  mint_amount1
else
  mint_amount2
end
end
end

export fun get_output_swap_infos(token_address, input_amount) do
if input_amount <= 0 do
throw code: 1, message: "input amount must be positive"
end

reserves = State.get("reserves", [token1: 0, token2: 0])

if reserves.token1 <= 0 || reserves.token2 <= 0 do
throw code: 2, message: "Insufficient output liquidity"
end

output_amount = 0
price_impact = 0
market_price = 0

token_address = String.to_uppercase(token_address)

fee = input_amount * State.get("lp_fee", 0.3) / 100
protocol_fee = input_amount * State.get("protocol_fee", 0) / 100
amount_with_fee = input_amount - fee - protocol_fee

if token_address == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" do
market_price = reserves.token2 / reserves.token1
amount = (amount_with_fee * reserves.token2) / (amount_with_fee + reserves.token1)
if amount < reserves.token2 do
  output_amount = amount
else
  throw code: 2, message: "Insufficient output liquidity"
end
else
market_price = reserves.token1 / reserves.token2
amount = (amount_with_fee * reserves.token1) / (amount_with_fee + reserves.token2)
if amount < reserves.token1 do
  output_amount = amount
else
  throw code: 2, message: "Insufficient output liquidity"
end
end

# This check is necessary as there might be some approximation in small decimal calculation
output_price = output_amount / input_amount
if output_amount > 0 && market_price > output_price do
price_impact = 100 - (output_price * 100 / market_price)
end

[
output_amount: output_amount,
fee: fee,
protocol_fee: protocol_fee,
price_impact: price_impact
]
end

export fun get_input_swap_infos(token_address, output_amount) do
if output_amount < 0 do
throw code: 1, message: "output amount cannot be negative"
end

reserves = State.get("reserves", [token1: 0, token2: 0])
token_address = String.to_uppercase(token_address)

if token_address == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" && output_amount >= reserves.token1 do
throw code: 2, message: "Insufficient output liquidity"
end

if token_address == "UCO" && output_amount >= reserves.token2 do
throw code: 2, message: "Insufficient output liquidity"
end

input_amount = 0
market_price = 0

lp_fee = State.get("lp_fee", 0.3) / 100
protocol_fee = State.get("protocol_fee", 0) / 100
price_impact = 0

if token_address == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" do
market_price = reserves.token1 / reserves.token2
input_amount = (output_amount * reserves.token2) / ((reserves.token1 - output_amount) * (1 - lp_fee - protocol_fee))
else
market_price = reserves.token2 / reserves.token1
input_amount = (output_amount * reserves.token1) / ((reserves.token2 - output_amount) * (1 - lp_fee - protocol_fee))
end

if input_amount > 0 do
# This check is necessary as there might be some approximation in small decimal calculation
output_price = output_amount / input_amount
if market_price > output_price do
  price_impact = 100 - (output_price * 100 / market_price)
end
end

[
input_amount: input_amount,
fee: input_amount * lp_fee,
protocol_fee: input_amount * protocol_fee,
price_impact: price_impact
]
end

export fun get_remove_amounts(lp_token_amount) do
reserves = State.get("reserves", [token1: 0, token2: 0])
lp_token_supply = State.get("lp_token_supply", 0)

token1_to_remove = 0
token2_to_remove = 0

if lp_token_supply > 0 && lp_token_amount < lp_token_supply do
token1_to_remove = (lp_token_amount * reserves.token1) / lp_token_supply
token2_to_remove = (lp_token_amount * reserves.token2) / lp_token_supply
end

[token1: token1_to_remove, token2: token2_to_remove]
end

export fun get_pool_infos() do
reserves = State.get("reserves", [token1: 0, token2: 0])
stats = State.get("stats", [
token1_total_fee: 0,
token2_total_fee: 0,
token1_total_volume: 0,
token2_total_volume: 0,
token1_total_protocol_fee: 0,
token2_total_protocol_fee: 0,
])

[
token1: [
  address: "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A",
  reserve: reserves.token1
],
token2: [
  address: "UCO",
  reserve: reserves.token2
],
lp_token: [
  address: 0x00000D299B994C7325649A329D40617644979C6E5085B880575375441F4EC6366112,
  supply: State.get("lp_token_supply", 0)
],
fee: State.get("lp_fee", 0.3),
protocol_fee: State.get("protocol_fee", 0),
stats: stats
]
end

fun get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount) do
final_token1_amount = 0
final_token2_amount = 0

if reserves.token1 > 0 && reserves.token2 > 0 do
token2_ratio = reserves.token2 / reserves.token1
token2_equivalent_amount = user_amounts.token1 * token2_ratio

if token2_equivalent_amount <= user_amounts.token2 && token2_equivalent_amount >= token2_min_amount do
  final_token1_amount = user_amounts.token1
  final_token2_amount = token2_equivalent_amount
else
  token1_ratio = reserves.token1 / reserves.token2
  token1_equivalent_amount = user_amounts.token2 * token1_ratio

  if token1_equivalent_amount <= user_amounts.token1 && token1_equivalent_amount >= token1_min_amount do
    final_token1_amount = token1_equivalent_amount
    final_token2_amount = user_amounts.token2
  end
end
else
# No reserve
final_token1_amount = user_amounts.token1
final_token2_amount = user_amounts.token2
end

[token1: final_token1_amount, token2: final_token2_amount]
end

fun get_user_transfers_amount(tx) do
contract_address = 0x0000AF33F129F682ED08B1423B1C9E555AFBF9325A0D0695A63726E192BC96BEDFA3

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 == "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A" 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 = 0x0000AF33F129F682ED08B1423B1C9E555AFBF9325A0D0695A63726E192BC96BEDFA3

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 = [
"00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A",
"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 = 0x00000D299B994C7325649A329D40617644979C6E5085B880575375441F4EC6366112

lp_amount = 0
transfers = Map.get(token_transfers, Chain.get_burn_address(), [])

for transfer in transfers do
if transfer.token_address == lp_token do
  lp_amount = transfer.amount
end
end

lp_amount
end

fun get_pool_balances() do
token2_balance = 0
if "UCO" == "UCO" do
token2_balance = contract.balance.uco
else
token2_id = [token_address: "UCO", token_id: 0]
token2_balance = Map.get(contract.balance.tokens, token2_id, 0)
end

token1_id = [token_address: "00005751A05BA007E7E2518DEA171DBBD67B0527C637232F923830C39BFF9E8F159A", token_id: 0]
[
token1: Map.get(contract.balance.tokens, token1_id, 0),
token2: token2_balance
]
end

Content (0 B)

State (264 B)

{
  "lp_token_supply": 79530.96361882,
  "reserves": {
    "token1": 9317.26926922,
    "token2": 703780.07219421
  },
  "stats": {
    "token1_total_fee": 138.22682208,
    "token1_total_protocol_fee": 0.0,
    "token1_total_volume": 46266.49119125,
    "token2_total_fee": 8498.40829479,
    "token2_total_protocol_fee": 0.0,
    "token2_total_volume": 2839605.78582592
  }
}
                  
Movements (0)

Ownerships (1)

  • Secret shared with 1 key

    Encoded secret

    BC6CF238FE71943A108CF178963C0CB4D937EE889372414FD60AFDC616EC37BB6C107B3C29EC3694B5CDF5D39ECFC746E436EBE4E9755F63E7A1473B

    Authorized keys

    • 000122A6CD9ED07E46835D6E88E5BD0BEE84C3F5E5DBF8E916AD9B2EC912C44AFEC2

Contract recipients (0)

Inputs (0)

Contract inputs (0)

Unspent outputs (0)

Proofs and signatures

Previous public key

00011DA74216C2BC026E6F19628C759800A47AD90E62F310A761EB2669CF3F2AED6E

Previous signature

48AB2D7B69753ED9F8E9A283C5F4D7547DBE86FF3EADA32633C2C9160B67B71ACF4C4BC9854200C21766B7EB916FEDF4455C00907E801942CDE0224E5470B603

Origin signature

3045022100D3E20FC7FD5ED0CE92856839C9A30ED3511089436FEAFF7EC4B1F28263FA5E03022059AC6E4BD064C387D6B6E004000264B9CB6F016AA61FE4E478FF386534F65F07

Proof of work

010204480DD0A3F06534B4F9B9D93AC3BCC7EA8437BAE24295DBCB92035EE4E5C7AC86DE42699A2F1481F9F892D528363680AF126B34DADED27CFC5CF4F778B7027D14

Proof of integrity

00DF49102EEE31678F59550E795F08DC7FED739F1DC6F1B468148BC6DD7CEB05EE

Coordinator signature

EBEC664EB925666A45DBE38A648B55FC489FDCCFFFF09840DFC54CBDF42AF21309398864EE1DEDB7586331852644597F669A5431628E32A2FEAE030233280D05

Validator #1 public key

0001A47FA8573AE1E7DFD48036DAE2006E1E6A857701F280A55503DA34C6F3BC7759

Validator #1 signature

018A5ED39482225A3E1075195258E98BBCB25F6CD86DCE0AA3CA4AA4E3B6D7C87C5B39C7613975B559CDEB0593F92B827FCAF4B906A432C4DEA6B513ECFD770E

Validator #2 public key

000105B4FDF46B9FE90C30A471DCE4D296CCCDC27242C6CDA6E48622F4330C646100

Validator #2 signature

20FB5F71AA4540A56032057257A87039BB37BC70B5B2EC566444351283A10C7C48BB64EF76B613FC74A5418034F11492F9EBA8379E0D70FD37C9986A731AAE0D

Validator #3 public key

0001AA2CB2D202420DADFCF965225B9F0493D1F148F07850C02BD27BD58234E9E58D

Validator #3 signature

A0AA1A69AD3DE70BD5708C34FA156229B7FA78DFB5DED37A9B21FCF9DF0156A4B538D6B7DC89620BEC18C60CCCD4980DAD8CE54230544C16796187985C64EF06

Validator #4 public key

0001172FBEC021CA921A9A771C312FCAD74E84CF0A466F5F662630C70E7BD8699587

Validator #4 signature

C99D4A98E74DB65934A780982F7E8129C433C79DBEF80E307D2B38740A5A489B45CD35854988B186B77DB52132DF3D65443495483A0ABCD762ED20EFA2B6C803

Validator #5 public key

0001917B62B721F89BD6739EECA00A37643F3D478DE77ADEA1CD331C538B039D0954

Validator #5 signature

F21DF5B5E7C833D59BB51A257C6D0D1D1FD347EEDEF858E0F1081989FA3C9B5FBEF5CD6C9CF984759F0AF0795F6A364CE1507AC8C73F46E9D986845A1FA8EC01