@version 1
condition triggered_by: transaction, on: add_pool(token1_address, token2_address, pool_creation_address), as: [
type: "transfer",
content: (
valid? = false
token1_address = String.to_uppercase(token1_address)
token2_address = String.to_uppercase(token2_address)
pool_exists? = get_pool_addresses(token1_address, token2_address) != nil
if token1_address != token2_address && !pool_exists? do
# Could create a new function Chain.get_transactions(list_of_address)
pool_transaction = Chain.get_transaction(pool_creation_address)
# Ensure tokens exists and lp token definition is good
token1_symbol = get_token_symbol(token1_address)
token2_symbol = get_token_symbol(token2_address)
valid_definition? = false
if token1_symbol != nil && token2_symbol != nil && pool_transaction != nil && pool_transaction.type == "token" do
expected_content = get_lp_token_definition(token1_symbol, token2_symbol)
valid_definition? = Json.parse(pool_transaction.content) == Json.parse(expected_content)
end
valid_code? = false
pool_genesis_address = nil
if valid_definition? do
# Ensure code is valid
pool_genesis_address = Chain.get_genesis_address(pool_creation_address)
expected_code = get_pool_code(token1_address, token2_address, pool_genesis_address, pool_creation_address)
valid_code? = Code.is_same?(pool_transaction.code, expected_code)
end
if valid_code? do
# Ensure liquidity is provided to the pool
valid? = List.in?(transaction.recipients, pool_genesis_address)
end
log("valid_definition? #{valid_definition?}")
log("valid_code? #{valid_code?}")
log("valid? #{valid?}")
end
valid?
)
]
actions triggered_by: transaction, on: add_pool(token1_address, token2_address, pool_creation_address) do
token1_address = String.to_uppercase(token1_address)
token2_address = String.to_uppercase(token2_address)
pool_genesis_address = Chain.get_genesis_address(pool_creation_address)
pool_id = get_pool_id(token1_address, token2_address)
pools = State.get("pools", Map.new())
pool_data = [
address: pool_genesis_address,
lp_token_address: pool_creation_address
]
pools = Map.set(pools, pool_id, pool_data)
State.set("pools", pools)
end
condition triggered_by: transaction, on: update_code(new_code), as: [
previous_public_key: (
# Router code can only be updated from the master chain of the dex
# Transaction is not yet validated so we need to use previous address
# to get the genesis address
previous_address = Chain.get_previous_address()
Chain.get_genesis_address(previous_address) == 0x0000339c1c65f0b2eb77af8ab68a38cbc6d2f6828b9ad3e90bb2e7fce3a99a428aff
),
code: Code.is_valid?(new_code)
]
actions triggered_by: transaction, on: update_code(new_code) do
Contract.set_type("contract")
Contract.set_code(new_code)
end
condition triggered_by: transaction, on: update_pools_code(), as: [
previous_public_key: (
# Pool code update can only be requested from the master chain of the dex
# Transaction is not yet validated so we need to use previous address
# to get the genesis address
previous_address = Chain.get_previous_address()
Chain.get_genesis_address(previous_address) == 0x0000339c1c65f0b2eb77af8ab68a38cbc6d2f6828b9ad3e90bb2e7fce3a99a428aff
)
]
actions triggered_by: transaction, on: update_pools_code() do
pools = State.get("pools", Map.new())
if Map.size(pools) > 0 do
for pool_info in Map.values(pools) do
Contract.add_recipient address: pool_info.address, action: "update_code", args: []
end
Contract.set_type("transfer")
end
end
fun get_pool_id(token1_address, token2_address) do
if token1_address > token2_address do
temp = token1_address
token1_address = token2_address
token2_address = temp
end
"#{token1_address}/#{token2_address}"
end
fun get_token_symbol(token_address) do
if token_address == "UCO" do
"UCO"
else
tx = Chain.get_transaction(token_address)
# Transaction must have type token
# Token must by fungible
symbol = nil
if tx != nil && tx.type == "token" do
token_definition = Json.parse(tx.content)
if token_definition.type == "fungible" do
symbol = Map.get(token_definition, "symbol", nil)
end
end
symbol
end
end
export fun get_pool_addresses(token1_address, token2_address) do
token1_address = String.to_uppercase(token1_address)
token2_address = String.to_uppercase(token2_address)
if token1_address > token2_address do
temp = token1_address
token1_address = token2_address
token2_address = temp
end
pool_id = "#{token1_address}/#{token2_address}"
pools = State.get("pools", Map.new())
Map.get(pools, pool_id, nil)
end
export fun get_pool_list() do
pools = State.get("pools", Map.new())
list = []
for pool_id in Map.keys(pools) do
pool = Map.get(pools, pool_id)
pool = Map.set(pool, "tokens", pool_id)
list = List.prepend(list, pool)
end
list
end
export fun get_pool_code(token1_address, token2_address, pool_address, lp_token_address) do
code = ""
token1_address = String.to_uppercase(token1_address)
token2_address = String.to_uppercase(token2_address)
pool_address = String.to_uppercase(pool_address)
lp_token_address = String.to_uppercase(lp_token_address)
if token1_address != token2_address do
if token1_address > token2_address do
temp = token1_address
token1_address = token2_address
token2_address = temp
end
code =
"""
@version 1
condition triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount), as: [
token_transfers: (
valid_amounts? = false
valid_liquidity? = false
user_amounts = get_user_transfers_amount(transaction)
if user_transfers.token1 > 0 && user_transfers.token2 > 0 do
lp_token_supply = State.get("lp_token_supply", 0)
reserves = State.get("reserves", [token1: 0, token2: 0])
final_amounts = nil
if lp_token_supply != 0 do
# Returns final_amounts.token1 == 0 in case of insufficient funds
final_amounts = get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount)
else
final_amounts = [token1: user_amounts.token1, token2: user_amounts.token2]
end
if final_amounts.token1 != 0 do
valid_amounts? = true
pool_balances = get_pool_balances()
# Amount = final amounts + potential current balance over reserve
token1_amount = final_amounts.token1 + (pool_balances.token1 - reserves.token1)
token2_amount = final_amounts.token2 + (pool_balances.token2 - reserves.token2)
lp_token_to_mint = get_lp_token_to_mint(token1_amount, token2_amount)
valid_liquidity? = lp_token_to_mint > 0
end
end
valid_amounts? && valid_liquidity?
)
]
actions triggered_by: transaction, on: add_liquidity(token1_min_amount, token2_min_amount) do
pool_balances = get_pool_balances()
user_amounts = get_user_transfers_amount(transaction)
lp_token_supply = State.get("lp_token_supply", 0)
reserves = State.get("reserves", [token1: 0, token2: 0])
final_amounts = get_final_amounts(user_amounts, reserves, token1_min_amount, token2_min_amount)
token1_to_refund = user_amounts.token1 - final_amounts.token1
token2_to_refund = user_amounts.token2 - final_amounts.token2
token1_amount = pool_balances.token1 - reserves.token1 - token1_to_refund
token2_amount = pool_balances.token2 - reserves.token2 - token2_to_refund
lp_token_to_mint = get_lp_token_to_mint(token1_amount, token2_amount)
lp_token_to_mint_bigint = Math.trunc(lp_token_to_mint * 100_000_000)
# Remove minimum liquidity if this is the first liquidity if the pool
# First liquidity minted and burned on pool creation
if lp_token_supply == 0 do
lp_token_to_mint_bigint = lp_token_to_mint_bigint - 10
end
token_specification = [
aeip: [8, 18, 19],
supply: lp_token_to_mint_bigint,
token_reference: 0x#{lp_token_address},
recipients: [
[to: transaction.address, amount: lp_token_to_mint_bigint]
]
]
new_token1_reserve = pool_balances.token1 - token1_to_refund
new_token2_reserve = pool_balances.token2 - token2_to_refund
State.set("lp_token_supply", lp_token_supply + lp_token_to_mint)
State.set("reserves", [token1: new_token1_reserve, token2: new_token2_reserve])
if token1_to_refund > 0 do
Contract.add_token_transfer(to: transaction.address, amount: token1_to_refund, token_address: "#{token1_address}")
end
if token2_to_refund > 0 do
if "#{token2_address}" == "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: "#{token2_address}")
end
end
Contract.set_type("token")
Contract.set_content(Json.to_string(token_specification))
end
condition triggered_by: transaction, on: remove_liquidity(), as: [
token_transfers: (
valid? = false
user_amount = get_user_lp_amount(transaction.token_transfers)
lp_token_supply = State.get("lp_token_supply", 0)
if user_amount > 0 && lp_token_supply > 0 do
pool_balances = get_pool_balances()
token1_to_remove = (user_amount * pool_balances.token1) / lp_token_supply
token2_to_remove = (user_amount * pool_balances.token2) / lp_token_supply
valid? = token1_to_remove > 0 && token2_to_remove > 0
end
valid?
)
]
actions triggered_by: transaction, on: remove_liquidity() do
user_amount = get_user_lp_amount(transaction.token_transfers)
pool_balances = get_pool_balances()
lp_token_supply = State.get("lp_token_supply")
token1_to_remove = (user_amount * pool_balances.token1) / lp_token_supply
token2_to_remove = (user_amount * pool_balances.token2) / lp_token_supply
new_token1_reserve = pool_balances.token1 - token1_to_remove
new_token2_reserve = pool_balances.token2 - token2_to_remove
State.set("lp_token_supply", lp_token_supply - user_amount)
State.set("reserves", [token1: new_token1_reserve, token2: new_token2_reserve])
Contract.set_type("transfer")
Contract.add_token_transfer(to: transaction.address, amount: token1_to_remove, token_address: "#{token1_address}")
if "#{token2_address}" == "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: "#{token2_address}")
end
end
condition triggered_by: transaction, on: swap(min_to_receive), as: [
token_transfers: (
valid? = false
transfer = get_user_transfer(transaction)
if transfer != nil do
swap = get_swap_infos(transfer.token_address, transfer.amount)
valid? = swap.output_amount > 0 && swap.output_amount >= min_to_receive
end
valid?
)
]
actions triggered_by: transaction, on: swap(_min_to_receive) do
transfer = get_user_transfer(transaction)
swap = get_swap_infos(transfer.token_address, transfer.amount)
pool_balances = get_pool_balances()
token_to_send = nil
if transfer.token_address == "#{token1_address}" do
pool_balances = Map.set(pool_balances, "token2", pool_balances.token2 - swap.output_amount)
token_to_send = "#{token2_address}"
else
pool_balances = Map.set(pool_balances, "token1", pool_balances.token1 - swap.output_amount)
token_to_send = "#{token1_address}"
end
State.set("reserves", [token1: pool_balances.token1, token2: pool_balances.token2])
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
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) == 0x00000dd757ac0a67fd619c1d1c400037a38cdb0471e6496807d8b850dc422e5ca3aa
)
]
actions triggered_by: transaction, on: update_code() do
params = [
"#{token1_address}",
"#{token2_address}",
0x#{pool_address},
0x#{lp_token_address}
]
new_code = Contract.call_function(0x00000dd757ac0a67fd619c1d1c400037a38cdb0471e6496807d8b850dc422e5ca3aa, "get_pool_code", params)
if Code.is_valid?(new_code) && !Code.is_same?(new_code, contract.code) do
Contract.set_type("contract")
Contract.set_code(new_code)
end
end
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 == "#{token1_address}" 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 == "#{token1_address}" do
ratio = reserves.token2 / reserves.token1
else
ratio = reserves.token1 / reserves.token2
end
end
amount * ratio
end
export fun get_lp_token_to_mint(token1_amount, token2_amount) do
lp_token_supply = State.get("lp_token_supply", 0)
reserves = State.get("reserves", [token1: 0, token2: 0])
if lp_token_supply == 0 || reserves.token1 == 0 || reserves.token2 == 0 do
# First liquidity
Math.sqrt(token1_amount * token2_amount)
else
mint_amount1 = (token1_amount * lp_token_supply) / reserves.token1
mint_amount2 = (token2_amount * lp_token_supply) / reserves.token2
if mint_amount1 < mint_amount2 do
mint_amount1
else
mint_amount2
end
end
end
export fun get_swap_infos(token_address, amount) do
output_amount = 0
fee = 0
price_impact = 0
reserves = State.get("reserves", [token1: 0, token2: 0])
token_address = String.to_uppercase(token_address)
if reserves.token1 > 0 && reserves.token2 > 0 do
fee = amount * 0.003
amount_with_fee = amount - fee
market_price = 0
if token_address == "#{token1_address}" do
market_price = amount_with_fee * (reserves.token2 / reserves.token1)
amount = (amount_with_fee * reserves.token2) / (amount_with_fee + reserves.token1)
if amount < reserves.token2 do
output_amount = amount
end
else
market_price = amount_with_fee * (reserves.token1 / reserves.token2)
amount = (amount_with_fee * reserves.token1) / (amount_with_fee + reserves.token2)
if amount < reserves.token1 do
output_amount = amount
end
end
if output_amount > 0 do
price_impact = ((market_price / output_amount) - 1) * 100
end
end
[
output_amount: output_amount,
fee: 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])
[
token1: [
address: "#{token1_address}",
reserve: reserves.token1
],
token2: [
address: "#{token2_address}",
reserve: reserves.token2
],
lp_token: [
address: 0x#{lp_token_address},
supply: State.get("lp_token_supply", 0)
],
fee: 0.3
]
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 = 0x#{pool_address}
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 == "#{token1_address}" do
token1_amount = transfer.amount
end
if transfer.token_address == "#{token2_address}" do
token2_amount = transfer.amount
end
end
end
[token1: token1_amount, token2: token2_amount]
end
fun get_user_transfer(tx) do
contract_address = 0x#{pool_address}
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 = [
"#{token1_address}",
"#{token2_address}"
]
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 = 0x#{lp_token_address}
lp_amount = 0
transfers = Map.get(token_transfers, Chain.get_burn_address(), [])
for transfer in transfers do
if transfer.token_address == lp_token do
lp_amount = transfer.amount
end
end
lp_amount
end
fun get_pool_balances() do
balances = Chain.get_balance(contract.address)
token2_balance = 0
if "#{token2_address}" == "UCO" do
token2_balance = balances.uco
else
token2_id = [token_address: "#{token2_address}", token_id: 0]
token2_balance = Map.get(balances.tokens, token2_id, 0)
end
token1_id = [token_address: "#{token1_address}", token_id: 0]
[
token1: Map.get(balances.tokens, token1_id, 0),
token2: token2_balance
]
end
"""
end
code
end
export fun get_lp_token_definition(token1_symbol, token2_symbol) do
if token1_symbol > token2_symbol do
temp = token1_symbol
token1_symbol = token2_symbol
token2_symbol = temp
end
lp_token = "lp_#{token1_symbol}_#{token2_symbol}"
Json.to_string([
aeip: [2, 8, 18, 19],
supply: 10,
type: "fungible",
symbol: lp_token,
name: lp_token,
allow_mint: true,
properties: [
description: "LP token of AESwap"
],
recipients: [
[
to: Chain.get_burn_address(),
amount: 10
]
]
])
end
Content (0 B)
{
"pools": {
"00001A4AB7AD0CE2B494C965C66FF2962692A5FE5ECB71B345ABB53BAD88A83A01F1/0000288BF6F0E12457B125DC54D2DFA4EB010BE3073CF02E10FB79B696180F55B827": {
"address": "00008526199282354F0CD6C3ACA8BB0E2946235ADBC5355C40137E68E8298C2D281C",
"lp_token_address": "000065EF4CA7A6467C6915FE0EEAE5E4792F3FD9C69F6B356C88E3CBC74C0F7D9640"
},
"00001A4AB7AD0CE2B494C965C66FF2962692A5FE5ECB71B345ABB53BAD88A83A01F1/00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4": {
"address": "0000CB7E77D7F0C3F07B7A97A1D79C932719BE616BBA16301B01CD7D897B2371715A",
"lp_token_address": "0000F98BCB81EF014F9F7C8FD12281E017209C177F3C93D275C90552F81BA847DBDB"
},
"00001A4AB7AD0CE2B494C965C66FF2962692A5FE5ECB71B345ABB53BAD88A83A01F1/UCO": {
"address": "0000C5618CA1340ECFAA24E7B1DD750A43E807BEB0DDDD878203716E5BEE2D68B434",
"lp_token_address": "0000D4B08F7C754731C7B2316AC173CA7AF2567D2F351706BA9E4789E63B7283D26C"
},
"0000288BF6F0E12457B125DC54D2DFA4EB010BE3073CF02E10FB79B696180F55B827/00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4": {
"address": "000037F83C51FB49AF412E766807AAA0639EF6D25A85CA688952CC6A1EC596703413",
"lp_token_address": "000045B382867CF7D02D27EF64C4D77E2A3028DA4907274204B66DC7B86D32924FFD"
},
"0000288BF6F0E12457B125DC54D2DFA4EB010BE3073CF02E10FB79B696180F55B827/UCO": {
"address": "0000151C7079B2344874DFDE4B7B982F127A4071E36C4726346A75E78319F83DB989",
"lp_token_address": "00005CC1FEA9F0E49CF34CB6E37230EDFB9FB8949963EFF7E3171F37BFFDE7D64A25"
},
"00003DF600E329199BF3EE8FBE2B8223413D70BCDD97E15089E6A74D94DE3F1173B4/UCO": {
"address": "0000BD2E4C70AA0996096FB3F949FC011159D0314365692047C5DA2D0153B13EAC2D",
"lp_token_address": "0000E2A41863FE1FA00F8E4C8CCA07C6735B79640D51FFD25FE35EA78C7389D1484F"
},
"00006E0EAF729C9CC2197DD12F705C04F32BBAB0B326DC261BA7D12E7C391324B94D/UCO": {
"address": "000026897C5E8ADE60CECFD5FD1B10F20B7F8E484A062A47EDA73F169157911FFC7A",
"lp_token_address": "0000B47F113ECE5966F245D770B218F95E676262B82A91804393A5FA6138C1578170"
},
"0000908C7DD6B39760EF3A29CD4173A16DCD2183EC2AB5BCF851335DC162DE2BD060/0000E7367B119C45B5D92363E0E6C3E0067A6AD9E0B8C7CC7AB475AFFB010B24E380": {
"address": "000038BB17EAB87A10163BD566B9BBC1659831591B33500AA38EB8AF635CD6595F00",
"lp_token_address": "000037AE361DEF8BC35882EAB5C30E8A9646C1A1759CC6495D237783FDEBF0A85678"
},
"0000908C7DD6B39760EF3A29CD4173A16DCD2183EC2AB5BCF851335DC162DE2BD060/UCO": {
"address": "00003222E8B3082CFFE5DB7BDD0E4F3EF4D4F48E2377A8CD691A7D4882E1CD315D0B",
"lp_token_address": "000017250802F4CD95E82776AB57981F1897D8CD37A71AA6BA9FD766A8D8AC7E8E45"
},
"0000AA56D7FA5AD3524A4EC074A0A3746E38CBC97054BFCB1A9221B348FE3638A0E8/UCO": {
"address": "0000213EBE0109C43A0C04E269771A5C825B9E0740FC6151B6A754813C2E8769AA1A",
"lp_token_address": "000064DF14F0C50C0EE7234BD394081FAAFCC53E4A38C712F489E0A53A147EA78716"
},
"0000D128A7B35D43136430E3389E2401EE4FEEE214FCC1EE3790D63360EF2B5405AE/UCO": {
"address": "00003F329BF47DD4389D30DF1AE087FA2928EEFC59F0DAD2A9D8075B6AF85785CFD8",
"lp_token_address": "0000F201818CAB03073AAE54E675DA1DB96FB9369AFAAECD90C3059C5D5FC5A4F227"
}
}
}
-
Secret shared with 1 key
Encoded secret
92E90F9696424439E74FB252A20E05D1A3C062418F54F236751490EED75F5D1D6BCB68C00ABE0D6C81BF5B344685BD2EC381EB504087F6DC82786BDA
Authorized keys
- 00017877BCF4122095926A49489009649603AB129822A19EF9D573B8FD714911ED7F
Contract recipients (0)
Inputs (0)
Contract inputs (0)
Unspent outputs (1)
-
From 000002A7...F5DEAt 2023-12-07 16:41:38 UTCAmount 0.00243166 UCO
Previous public key
000196AA4E698A7FA09C9F92F600326AAA32F49C3A46285CEFDAC310219EBDD405E0
Previous signature
2DE289E9C703A947A85B12E40BB33516A6ED8F2DF5A7D368CA578FEDD01212B9F5083C4F973FA82F8700660DE7B43B2EE9C5B05B730D6E1B231F3EC6FC3BDF08
Origin signature
3046022100B728F4FADC1F125315360A626B80536053FABA969EB9637A7E6BF6C2AB3AC27C022100ABA76F61973F5904D93F8DEE96A0E798652A0AF29BFBB11C80E662C09C52781E
Proof of work
010204B3B2A53580086B9F36919CF40ABC55904729F78BF43673E216FAC1EB2451DD1E521879C6588F0CB09B150A103A39A73E2816B5ADF51F0721348BA3A66C33023B
Proof of integrity
00F6AA60CC7D03F95FAB218EF6E18E8F776F3CB7A93D1E611906D686C035F38140
Coordinator signature
4D0C59931E97E58454866073800FC275E3928BACBC56B58B01247246DB8AC394835C332E0C83DCD05804257597A812ACB182A5231F68CC24FBC78B0B6795EA03
Validator #1 public key
0001B0A94804BF8ECC9897075C6207FF63EF4D339F57A0349888E6B77CD47DB53EF3
Validator #1 signature
028DDD1BCC99A7CFDFE4D345BB7E2A5A2F0CCD516E3D94F578DE5A21F8B993ED8F8A03AC63C76F6773ED0D2BCED7476108955768C7EAA57863833B79528E4E0B
Validator #2 public key
00011B58ED42235461734EAF253BD97A80B92899ABCC3BE680D44B6825DD2A88A947
Validator #2 signature
6CBB79C6DCC9504EE19C62BF9B589E372FAEB360D0AFC26A74E643B7B32D1E8096B8A21DA82536EC4015BFF6837CBB67CDA08AABE4C35BAFE8E6029BFD69FA05