owned this note
owned this note
Published
Linked with GitHub
# Aurora FT formal specification
```
//== Types section
type NearAccount = String
type EthAddress = [u8; 20]
type EthAccount = EthAddress
type Account = NearAccount | EthAccount
type Balance = u128
type U256 = [u8; 32]
type DepositedEvent = {
eth_custodian_address: EthAddress
sender: EthAddress
recipient: NearAccount
amount: Balance
fee: Balance
}
type Proof = [u8]
type EthConnector = {
prover_account: AccountId
eth_custodian_address: EthAddress
}
type FunginleToken = {
total_supply: Balance
total_supply_near: Balance
total_supply_eth: Balance
}
type Contract = {
connector: EthConnector
ft: FunginleToken
}
// Aurora Engine representation
type Engine = {}
//== Data state section
// Contract data
let contract = Contract
// Map contains EVM accounts and related balances
let balances = Map<Accoun, Balance>
// Map contains alias of NEAR accounts to ERC20 Eth address
let near_tokens = Map<Account, EthAddress>
// Map contains alias of NEAR accounts to Relayer Eth address
let relayers = Map<Account, EthAddress>
// Map of used proof data
let proofs = Map<String, Proof>
// Aurora engine state
let engine = Engine
//== Contract methods section
// Deploy ERC20 contract to EVM and set alias of NEAR account and ERC20 address
let deploy_evm_token(account: NearAccount, erc20_smart_contract: [u8]) =
let erc20_address: EthAccount = engine.deploy_eth_contract(erc20_smart_contract)
near_tokens[account] = erc20_address
// Register Relayer - set alias between Predecessor and Relayer Eth address
let register_relayer(relayer_eth_address: EthAddress) =
let account: NearAccount = engine.predecessor_id()
relayers[account] = relayer_eth_address
// Deposit tokens to Aurora
let deposit(proof_data: Proof) =
// Fetch event form proof data
let event: DepositedEvent = event_from_proof(proof_data)
// Parse event message data
let message: [String] = event.recipient.split(':')
// Calculate proof key
let proof_key: String = sha256(proof_data)
// Call cross-contract call to verify Proof
let promise1 = async verify_log_entty(contract.prover_account, proof_data)
let promise2 =
// If splitted message has langth > 1, it should be
// Eth accounts logic
if len(message) > 1 then
let new_owner_id: NearAccount = engine.current_account_id()
let receiver_id: NearAccount = message[0]
let memo = None
let fee: U256 = event.fee
// Set new message data
let msg: String = engine.predecessor_account_id() + ":" + hex(fee) + message[1]
// We put relayer but will not minting fee directly in finish_deposit
let relayer = engine.predecessor._id()
// Cross-contract call to finish deposit
async finish_deposit_near(engine.current_account_id(), relayer, new_owner_id, event.amount, event.fee, proof_key, msg)
else
// NEAR accounts logic
let new_owner_id: NearAccount = message[0]
// Relayer in current logic is predecessor for minting fee
let relayer = engine.predecessor._id()
// Empty message for NEAR accounts
let msg = None
/ Cross-contract call to finish deposit
async finish_deposit_near(engine.current_account_id(), relayer, new_owner_id, event.amount, event.fee, proof_key, msg)
// Promises executed async but one by one
await promise1 |> promise2
// Finish deposit for NEAR accounts
// Mint tokens for NEAR & Eth accounts. For Eth account rise additional
// logic with ft_transfer_call cross contract call
let finish_deposit_near(new_owner_id: NearAccount, relayer: NearAccount, amount: Balance, fee: Balance, proof_data: Proof, msg: option String) =
// Check result from verify_log_entry
if promise_result() == false then
raise_error()
// Record proof. Proof shouldn't be reusable
record_proof(proof_key)
// Check mint type for switching minting logic
if msg == None then
// NEAR accounts
// Mint tokens to owner
mint_near(new_owner_id, amount - fee)
// Mint fee
mint_near(relayer, fee)
async ft_transfer_call(current_account_id(), receiver_id, amount, memo, msg)
else
// Eth accounts
// Mint tokens to Aurora contract
mint_near(new_owner_id, amount)
// Call transfer_call cross contract
let promise1 = async ft_transfer_call(current_account_id(), receiver_id, amount, memo, msg)
await promise1
// Check is proof already exist and save to storage
let record_proof(proof_key: String) =
if proofs[proof_key].exist()
raise_error()
proofs[proof_key] = 1
// Mint tokens for NEAR balance
let mint_near(owner_id: NearAccount, amount: Balance)
balances[owner_id] += amount
total_supply_near += amount
total_supply += amount
// Mint tokens for ETH balance
let mint_eth(address: EthAddress, amount: Balance)
balances[address] += amount
total_supply_eth += amount
total_supply += amount
// Burn tokens for NEAR balance
let burn_near(owner_id: NearAccount, amount: Balance)
balances[owner_id] -= amount
total_supply_near -= amount
total_supply -= amount
// Transfer call - transfer tokens with call-back function - ft_on_transfer
// that will invoked as cross contract call
let ft_on_transfer(receiver: NearAccount, amount: Balance, memo: option String, msg: String) =
// Transfer tokens between NEAR accounts
let sender: NearAccount = predecessor_id()
balances[sender] -= amount
balances[receiver] += amount
// Cross contract call from receiver account
let promise1 = async ft_on_transfer(receiver, amount, msg)
// Cross contract call resolve transfer
let promise2 = async ft_resolve_transfer(current_account_id(), receiver, amount)
// Async promises execution but one by one
await promise1 |> promise2
// Resolve transfer for unused tokens
let ft_resolve_transfer(receiver: NearAccount, amount: Balance, sender: NearAccount) =
let unused_amount: Balance = promise_return(0)
balances[receiver] -= unused_amount
balances[sender] += unused_amount
// ft_on_transfer - call-back function
let ft_on_transfer(receiver: NearAccount, amount: Balance, msg: String) =
// Parse message
let message = msg.split(":")
let relayer: NearAccount = message[0]
let fee: U256 = message[1][..32]
let recipient: EthAddress = message[1][32..52]
// Check is call from current (Aurora) contract
if engine.current_account_id() == engine.predecessor_account_id() then
// Transfer from NEAR account to Eth account
burn_near(engine.current_account_id(), amount)
mint_eth(recipient, amount)
else
let erc20_address: EthAddress = near_tokens[engine.predecessor_account_id)_]
let relayer_address: EthAddress = relayers[relayer]
// Call ERC20 contract for transfer tokens
engine.call_with_args()
// Transfers fee to Relayer
if fee > 0 then
balances[recipient] -= fee
balances[relayer_address] += fee
```