Skip to content

Operations

Jean-Baptiste Dusseaut edited this page Apr 27, 2021 · 12 revisions

Operations

Backups

The most critical parts to backup are of course :

  • ipns key

  • signing keys

If you use a cloud hsm, make sure to activate some deletion protections, to avoid any accidental removal.

Beside that, since a signer can always rebuild its state, if it still has control of its keys (signing + ipns), backing up its local state or its ipfs repository is not mandatory. It’s just a matter of rebooting faster in case of data loss on a server. Of course, if you lose your ipfs repository, users won’t be able to retrieve your signatures if no node on the network has a copy. That’s why BenderLabs runs a instance of wrap-indexer, that amongs other thing, will pin all events produced by the quorum.

Changing payment address

By default, fees will be distributed to the implicit account associated with the signer signing key. It’s possible to instruct the contract to dispatch fees to another payment address.

Quorum contract exposes an entrypoint set_signer_payment_address for this purpose:

(pair %set_signer_payment_address
    (address %minter_contract) (1)
    (pair
        (string %signer_id) (2)
        (signature %signature) (3)
    )
)
  1. Address of the minter contract

  2. Signer’s IPFS key (as returned by the keys endpoint)

  3. A signature, described below

The signature will be checked againt the public key associated with this signer_id. If the signature is valid, the sender address will be used as the new payment address. That way, we check that the caller is both in control of the signer public key, and obviously, the sender private key. To prevent replay attack, each signer is associated with a counter that will increment with every call.

The payload to sign is as follow:

(
    chain_id (1)
    *
    address (2)
) *
(
    nat (3)
    *
    (
        address (4)
        * address (5)
    )
)
  1. Chain id the contract is running on

  2. Quorum contract address

  3. Current counter for this signer. Starts at 0. Can be retrieve later on in the quorum contract storage

  4. Minter contract address

  5. Sender address

Admin api exposes an enpoint to produce this signature.

Step by step guide

  1. Build the signature

    PAYLOAD=`cat <<EOF
    {
        "address":"tz…",(1)
        "counter":0 (2)
    }
    EOF`;
    
    curl -X POST -H "Content-Type: application/json" -d "${PAYLOAD}" http://signer.node:5000/signatures/payment_address;
    1. New payment address

    2. Current counter. can be left to 0 the first time around

      You’ll get an answer looking like:

      {
          "signature" = "<signature in base58>",
          "quorum":{
              "quorumContract": "<targeted quorum contract>,
              "chainId": "<targeted chain id>",
              "minterContract": "<targeted minter contract>"
          },
          "parameters":{
              "counter": <counter used>,
              "address": "<new payment address>"
          }
      }

      Extracts the information you need for next step (quorum contract, minter contract, signature)

  2. Call the quorum contract, using the proper sender

    tezos-client call <Quorum contract address> \
    from <Your new payment address> \
    --entrypoint 'set_signer_payment_address'
    --arg 'Pair "<Minter contract address>" (Pair "<ipfs key>" "<signature>")'

Fees managenent

Minter contract is technically, the owner of all fees generated. It keeps an internal ledger to know who is entitled to what. This ledger is updated in different ways:

  • each time a wrap/unwrap occurs, the minter contract increases it own balance

  • each time distribute_tokens or distribute_xtz is called, minter contract dispatches it balance along signers, dev pool and staking contract

  • each time anyone who owns a balance withdraw its funds

So in a nutshell, only withdraw_all_tokens, withdraw_all_xtz, withdraw_token generate an actual transfer.

An offchain view exists to extract the token amount owned to a given address : get_token_reward To know how many tokens are pending distributon, the same view can used, just passing minter contract address as parameter.

Distribution

Minter contract, when one of the distribution endpoint is called, will update to the appropriate amount the balance of each signer. To do so, it needs to know the current quorum members. That’s why these entrypoints are permissioned to a role called oracle, in charge of relaying quorum members. For now, this role is held by the quorum contract itself, and will just forward what it has in storage. Later on more sofisticated rules could be introduced.

Since the token list can grow unbounded, tokens to be distributed must be specified as parameter.

So, to trigger a distribution, one must call distribute_tokens_with_quorum from the quorum contract. It’s permissionless, and accept this parameter:

  (pair %distribute_tokens_with_quorum
    (address %minter_contract)
    (list %tokens (pair address nat)))

One such invocation could look like:

tezos-client transfer 0 from %YOUR_ADDRESS% \
to KT1DLif2x9BtK6pUq9ZfFVVyW5wN2kau9rkW \
--entrypoint 'distribute_tokens_with_quorum' \
--arg 'Pair "KT1MTnKjFSN2u4myPRBqnFuCYCPX8kTdUEnv"  { Pair "KT18fp5rcTW7mbWDmzFwjLDUhs5MeJmagDSZ" 0 ;  Pair "KT18fp5rcTW7mbWDmzFwjLDUhs5MeJmagDSZ" 1 }'

Withdrawal

The withdrawal logic is very straighforward : the minter contract will send any amount associated with the sender address to the sender itself.

keep in mind that unless you change it, all fees will be associated with the implicit account deduced from the signer public key, so you would need to call withdraw with your signing key.

For instance, the withdraw all initial 21 tokens out of the contract:

transfer 0 from %YOUR_ADDRESS% \
to KT1MTnKjFSN2u4myPRBqnFuCYCPX8kTdUEnv \
--entrypoint 'withdraw_all_tokens' \
--arg 'Pair "KT18fp5rcTW7mbWDmzFwjLDUhs5MeJmagDSZ" { 0 ; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20 }'

And to withdraw fees collected in WRAP, if any :

transfer 0 from %YOUR_ADDRESS% \
to KT1MTnKjFSN2u4myPRBqnFuCYCPX8kTdUEnv \
--entrypoint 'withdraw_all_tokens' \
--arg 'Pair "KT1LRboPna9yQY9BrjtQYDS1DVxhKESK4VVd" { 0  }'

Admin API

Signer node exposes a minimal admin api. It is not protected, so make sure not to expose it on the internet:

GET /keys

returns keys in use by this signer instance. Usefull to be onboarded as a quorum member, since it contains everything required.

{
    "tezosKey":"<tezos public key, in base58>",
    "ethereumKey": "<ethereum signing address>",
    "ipnsKey": "<ipfs public key used to publish events>"
}

GET /status

returns the signer current status. Can serve as a healtcheck endpoint.

{
    "head": "<CID of last event published>",
    "tezosLevel": <last tezos level observed>,
    "ethereumLevel": <lest ethereum level observed>
}

POST /signatures/payment_address

used to signed a change payment address request. By default, minter contract will collect fees for a specific signer under the implicit account associated with its public key. This could prove to be unpractical, and as a mater of fact, we discourage storing assets under this address.

It is possible to change its payment address, calling the proper endpoint on quorum contract, but it will require a signature coming from its public signing key. Also, the quorum contract expects the new payment address to be the SENDER address To protect against replay attack, quorum contract expect the signed to payload to include a counter, specific to each signer, and incremented with each successfull call.

This process is described in more details in the contract documentation.

Payload, Content-Type=application/json:

{
    "address":"<new payment address. Should be the `SENDER` that quorum contract will observe> ",
    "counter": <current signer counter in quorum contract>
}

Response:

{
    "signature" = "<signature in base58>",
    "quorum":{
        "quorumContract": "<targeted quorum contract>,
        "chainId": "<targeted chain id>",
        "minterContract": "<targeted minter contract>"
    },
    "parameters":{
        "counter": <counter used>,
        "address": "<new payment address>"
    }
}

This response can be used then to actually call the quorum contract

Clone this wiki locally