fio.erc20 - wFIO Contract Specification

Actions

Actions

Description

Actions

Description

wrap

mint to address with oracle approvals

unwrap

burn (called by user)

regoracle

register oracle

unregoracle

unregister oracle

regcust

register custodian

unregcust

unregister custodian

pause

pause wrap, unwrap or any built-in erc20 functions

unpause

unpause wrap, unwrap or any build-in erc20 functions

getOracle

Get oracle status by ethereum address

getCustodian

Get custodian status by ethereum address

getApproval

getApproval status by obtid

  • If fewer than 3 oracles have approved a wrap, getApproval returns:

    • Number of approvals

    • Ethereum address where the wfio will be sent to

    • Amount

1 2 3 4 5 Result { '0': '1', '1': '0x009310e41f4746AFeca3Ac713e070598067A32db', '2': '30000000000' }
  • Once 3 oracles have been approved, the approval is removed from the vector so returns zeros:

1 2 3 4 5 Result { '0': '0', '1': '0x0000000000000000000000000000000000000000', '2': '0' }

State Variables

State variables

Description

State variables

Description

custodian_count

Keeps track of the number of custodians active in the oracle. Required for consensus math

oracle_count

Keeps track of the number of custodians active in the oracle. Required for consensus math

uoracmapv

Incrementer used to generate unique id for unregoracle approval mapping

roracmapv

Incrementer used to generate unique id for regoracle approval mapping

ucustmapv

Incrementer used to generate unique id for unregcust approval mapping

rcustmapv

Incrementer used to generate unique id for regcust approval mapping

upausmapv

Incrementer used to generate unique id for unpause approval mapping

pausemapv

Incrementer used to generate unique id for pause approval mapping

owner

Used to store contract owner (msg.sender) when deployed

oraclelist

A list of oracle addresses

Events

Events

Description

Events

Description

wrapped

Event emitted when wrap has completed.
emit wrapped(account, amount, obtid);

unwrapped

Event emitted when user has unwrapped tokens.
emit unwrapped(fioaddress, amount);

custodian_registered

Event emitted when a custodian has been registered
event custodian_registered(address account, uint256 eid);

custodian_unregistered

Event emitted when a custodian has been unregistered
event custodian_unregistered(address account, uint256 eid);

oracle_registered

Event emitted when an oracle has been registered
event oracle_registered(address account, uint256 eid);

oracle_unregistered

Event emitted when an oracle has been unregistered
event oracle_unregistered(address account, uint256 eid);

Paused

Event emitted when the contract has been paused by custodians

Unpaused

Event emitted when the contract has been unpaused by custodians

Mappings

Mappings

Members

Description

Mappings

Members

Description

Custodians
mapping (address=>custodian) custodians

custodian
- active

Keeps track of the custodians that registered another custodian and their activation

Oracles
mapping (address=>oracles) oracles

oracle
- active

Keeps track of the custodians that registered an oracle and the oracles activation count

Approvals
mapping (bytes => bool) approver;

pending
- approved
- account
- approvers

Keeps track of the approvals by obtid, the number of approvals, and the details of the approval
This table is also used for tracking pause/unpause, oracle and custodian registration approvals, the account and approvers state variables remain

 

Modifiers

Modifiers (Perms)

Action

Description

Modifiers (Perms)

Action

Description

onlyOracle

wrapunwrap

Only wFIO oracle may use this function

onlyCustodian

regoracle
unregoracle
regcust
unregcust

Only wFIO custodian may use this function

whenPaused

unpause

Built into erc20 pausable security contract. Keeps an action from being called when paused

whenNotPaused

pause
wrap
unwrap

Built into erc20 pausable security contract. Keeps an action from being called when unpaused

 

Misc. Requirements

Issue

Summary

Decision

Issue

Summary

Decision

Max supply

Should we put in a max supply to prevent over-minting of wFIO? This would track the maximum number of wFIO that could be in circulation.

Not needed

Reason: if the ERC20 contract gets taken over an additional wFIO is minted, the most likely course of action will be to fork the contract and invalidate the bad transactions.

Max transaction size

Should we put a max transaction size limit on mint into the ERC20 contract.

Not needed

ERC20 contract key

What is the status of the key used to set the contract?

Key should only be used for spinning up the contract and should be burned.

“Pause” function for Custodians

What is the process for locking the wFIO contract if it gets compromised?

Adam: contract is pausable. Tracked in: https://fioprotocol.atlassian.net/browse/BD-2585

 

Oracle “Admin” functions

Do we need to enable the ability for Oracles to call various contract actions such as approve, transfer, mint, etc.

This can be performed in a couple of ways:
1 - The Oracles vote in who can execute the next essential action as follows:
Oracle 1 executes approval action (not to be confused with erc20 approve) to mint using FIO obtid xxxxxxxx
Oracle 2 executes approval action to transfer for the same FIO obtid to Alice

Oracle 3 executes approval action for transfer, but wrong recipient is provided. Trx goes to Alice defined by oracle 1 and 2

2 - The Oracles can sign the next transfer action as a multisig
This could be quite costly on the ethereum chain, but is possible to implement.
Example of multisig on ethereum https://github.com/christianlundkvist/simple-multisig/blob/master/contracts/SimpleMultiSig.sol

Pawel will create an Oracle/Custodian Wrapping Manual that includes use cases for how to respond to errors with wrap and unwrap.

Tracked in: https://fioprotocol.atlassian.net/browse/WP-522

Custodian “Admin” functions

Are there contract actions that should be exposed to Custodian “admin” approval?

  • Pause switch is an admin function.

  • Use case: refunds. If someone calls unwrap to the wrong address and it gets lost. We may want to enable the ability for Custodians to call 2/3+1 approval for a “mint” refund.

    • This can already be done by the Oracles calling wrap to a specific Ethereum address.

Todo: Pawel will create an Oracle/Custodian Wrapping Manual that includes use cases for how to respond to errors with wrap and unwrap.

Tracked in: https://fioprotocol.atlassian.net/browse/WP-522

 

Unwrap fee

Is there a fee for unwrap?

On unwrap, the user pays the gas fees.

ERC-20 contract key burn

Once we spin up the ERC-20 contract with multiple custodian keys, we will burn the contract key

https://fioprotocol.atlassian.net/browse/BD-2586

 

Wrap/Unwrap

wrap

Create wFIO on Ethereum chain.

Registering oracles

  • wFIO is created using the wrap action

Implementation

  • New action: wrap

Request body

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

account

Yes

string

Public address on ETH blockchain where wrapped FIO should be delivered.

amount

Yes

uint256

Amount of wFIO (in SUFs) to unwrap.

obtid

Yes

string

FIO chain transaction ID

Example

1 2 3 4 5 { "account": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", "amount": 100000000000, "obtid": "dfe50aad8e2271f84f87b8e603776d7e7970c636bb899c8993c08e9e2d21c106" }

Processing

  • Request is validated per Exception handling.

  • Consensus required. Transaction is executed when all registered oracles have called wrap (submitted their “observation”).

    • Current:

      • 100% of oracles needed to approve (Minimum of 3 oracles) call wrap to get it approved

      • The final oracle approval executes the wrap.

  • wFIO is minted and transferred to account

  • Cannot be called when contract is in paused state

Exception handling

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Invalid amount

Transfer amount is not valid.

400

"Invalid amount"

Invalid public address

Recipient public address is not valid

400

"Invalid public address"

No authority

The signer is not a registered Oracle and does not have authority to call this function

403

"Only a wFIO Oracle may call this function"

Contract paused

Contract is paused (built-in)

400

"Pausable: paused"

unwrap

Convert wFIO on Ethereum chain to FIO Tokens on FIO chain.

Implementation

  • New action: unwrap

Processing

  • Called by the user

  • Cannot be called when the contract is in paused state

Fees

  • User [Alice] pays the unwrap gas fees.

Request body

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

amount

Yes

uint256

Amount of wFIO (in SUFs) to unwrap.

fio_address

Yes

String

The FIO Address where FIO Tokens should be delivered.

Example

1 2 3 4 { "amount": 100000000000, "fio_address": "alice@wallet" }

Processing

  • Request is validated per Exception handling.

  • No Oracle Consensus required.

  • Contract burns wFIO and event is emitted

Exception handling

 

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Invalid FIO address

Recipient public address is not valid

400

"Invalid FIO address"

Invalid amount

Transfer amount is not valid.

400

"Invalid amount"

Insufficient balance

Balance is less than amount + oracle fee + chain fee

400

"Insufficient balance"

No authority

The signer is not a registered Oracle and does not have authority to call this function

403

"Only a wFIO Oracle may call this function"

Contract paused

Contract is paused (built-in)

400

"Pausable: paused"

 

Oracles - register/unregister

regoracle

Register Oracle.

Registering oracles

  • Each Oracle is registered by custodians using regoracle action.

Implementation

  • New action: regoracle

Request body

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

account

Yes

Ethereum public address

Ethereum address owned by the Oracle.

Example

 

1 2 3 { "account": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" }

Processing

  • Request is validated per Exception handling.

  • Consensus required.

  • Oracles are registered by custodians. 2/3+1 of active custodians are required to complete registration of a new oracle.

  • A minimum of 3 oracles is required to approve a wrap transaction.

  • After approval, the Ethereum address is registered as a valid Oracle.

Exception handling

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Invalid address

Ethereum address is not valid

400

"Invalid address"

No authority

The signer is not a registered Custodian and does not have authority to call this function

403

"Only a wFIO custodian may call this function"

Already registered

The Ethereum address is already registered as an Oracle

400

“Oracle is already registered”

unregoracle

Unregister Oracle.

Implementation

  • New action: unregoracle

Request body

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

account

Yes

Ethereum public address

Ethereum address owned by the Oracle.

Example

1 2 3 { "account": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" }

Processing

  • Consensus required. Oracle is removed after 2/3+1 Custodians have called unregoracle with same ethereum account.

  • Ethereum address is removed as a valid Oracle.

  • A minimum of 3 oracles must be maintained. If only 3 Oracles are registered, unregoracle can not be called.

  • Once an account has been unregistered as an oracle, it cannot be re-registered. If the same oracle gets unregistered and wants to re-register, they will need to generate a new key/account.

Exception handling

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Invalid oracle

Oracle is not registered

400

"Invalid oracle"

No authority

The signer is not a registered Custodian and does not have authority to call this function

403

"Only a wFIO custodian may call this function"

 

Custodians - register/unregister

regcust

Register Custodian

Registering Custodians

  • Each Custodian is registered using regcust action.

Implementation

  • New action: regcust

Request body

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

account

Yes

Ethereum public address

Ethereum address owned by the Custodian.

Example

1 2 3 { "account": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" }

Processing

  • Request is validated per Exception handling.

  • Consensus required. Custodians are registered as follows:

    • The initial 10 custodians are set upon contract deployment by the contract owner.

    • Subsequently, 2/3+1 of active custodians must call regcust to register a new custodian.

  • Ethereum address is added as a valid Custodian.

Exception handling

Error condition

Trigger

Type

fields:name

fields:value

Error message

Error condition

Trigger

Type

fields:name

fields:value

Error message

Invalid address

Ethereum address is not valid

400

"account"

Value sent in, e.g. "invalid account"

"Invalid address"

No authority

The signer is not a registered Custodian and does not have authority to call this function

403

 

 

"Only a wFIO custodian may call this function"

Already registered

The Ethereum address is already registered as an Custodian

400

"account"

 

“Custodian is already registered”

 

unregcust

Unregister Custodian.

Implementation

  • New action: unregcust

Request body

 

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

account

Yes

Ethereum public address

Ethereum address owned by the Custodian.

Example

1 2 3 { "account": "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" }

Processing

  • Request is validated per Exception handling.

  • Consensus required. Custodian is removed after 2/3+1 of active custodians have called unregcust the same Ethereum address.

  • Ethereum address is removed as a valid Custodian.

  • A minimum of 7 Custodians must be maintained. If only 7 Custodians are registered, unregcust can not be called.

  • A custodian can not singlehandedly unregister themselves. All changes require 2/3+1. Bug, the custodian can call unregcust for themselves and be counted in the 2/3+1.

Exception handling

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Invalid custodian

Custodian is not registered

400

"Invalid custodian"

Invalid address

Ethereum address is not valid

400

"Invalid address"

No authority

The signer is not a registered Custodian and does not have authority to call this function

403

"Only a wFIO custodian may call this function"

pause

Pause contract.

Implementation

  • New action: pause

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

None

No

 

 

 

Processing

  • Any custodian can pause/unpause the erc20 contract.

Exception handling

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Contract paused

Contract is already paused (built-in)

400

"Pausable: paused"

Already approved

Custodian already called pause

400

“msg.sender has already approved this pause”

unpause

Unpause contract.

Implementation

  • New action: unpause

Parameter

Required

Format

Definition

Parameter

Required

Format

Definition

None

No

 

 

 

Processing

  • Any custodian can pause/unpause the erc20 contract.

Exception handling

Error condition

Trigger

Type

Error message

Error condition

Trigger

Type

Error message

Contract unpaused

Contract is already unpaused (built-in)

400

"Pausable: unpaused"

Already approved

Custodian already called unpause

400

“msg.sender has already approved this unpause”

 

Ethereum json rpc error codes:

https://eth.wiki/json-rpc/json-rpc-error-codes-improvement-proposal

Example erc20 response body:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 { tx: '0x3c9ffdcf06ac984b93f5c302cf63bdb33ddb9479eba34737dc1ff3cf819ef0a7', receipt: { transactionHash: '0x3c9ffdcf06ac984b93f5c302cf63bdb33ddb9479eba34737dc1ff3cf819ef0a7', transactionIndex: 0, blockHash: '0xc3503388ba0748373ab2596609b001391636a9a1d469fca73352a2f5709595af', blockNumber: 2, from: '0x996e32a723cfe4afcb30f5ee3db78808ee816114', to: '0x5f953f03c166d1609101ebfb7286b3526fea768b', gasUsed: 70446, cumulativeGasUsed: 70446, contractAddress: null, logs: [], status: true, logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', rawLogs: [] }, logs: [] }