1.0.2 • Published 3 years ago

@randlabs/bridge-algorand v1.0.2

Weekly downloads
-
License
ISC
Repository
github
Last release
3 years ago

StakerDAO Bridge

StakerDAO Bridge contracts and interface for Algorand.

Each Swap in this Bridge has two main components, the stateful contract application and the escrow.

The application is used to keep track of which swaps are active at any time. In order to do this in Algorand, we need to have local storage for each active Swap. We need to create an escrow account for each swap that is made.

This escrow account is a TEAL stateless contract that only allows certain transactions to be made, specifically OptIn and CloseOut to the main contract. If an user wants to make a lock to the contract, it needs to create this escrow account that will OptIn to the application and hold the funds. The Escrow needs to be funded with Algos, it needs to pay the transaction fees and Application OptIn requires the account to have a minimum amount of funds. The escrow account will statically hold the hash of the account in its code, the rest of the swap data will be stored in the local storage at the main contract when the escrow opts in.

After that, if it was not confirmed initially, the locker is allowed to directly call the application to confirm the swap. To finish the swap, either the locker or the reedemer can make the Escrow CloseOut from the contract and take the funds. If the receiver of the funds in the transaction is the locker the contract will check for the release-time, if it's the reedemer it will check for the preimage of the hash in the parameters. In both cases the Fee will go to the redeemer.

Components

swap-escrow.teal

This smart contract keeps the user tokens locked while the swaps are cleared. This contract is stateless, it will hold the hash of the secret statically and the application ID that is allowed to interact with (The main contract). Since this contract needs to be compiled dynamically for each swap that is made, these template parameters need to be replaced in the contract code before being compiled (A simple text replace will suffice):

  • TMPL_APP_ID: Application ID of the main contract (integer)
  • TMPL_HASH: The hash of the secret. (Hexa integer, ie 0x...)
  • TMPL_FROM: Address of the account sending the assets (address)

Please note that since this contract it's stateless it doesn't need to be deployed. You just need the code to be able to sign transactions. This code will hash into a unique address, and allow you to send transactions from it as long as you have the code as proof. The code then will restrict which kind of transactions you can make, this is what makes external parties unable to take funds from it, and disallows cheating from involving parties.

token-swap.teal

It handles both application calls from the escrow and also handles the locker confirmation step. It also has template parameters, but only needs to be deployed once:

  • TMPL_ASA_ID: The asset ID to be swapped. i.e. wAlgo (Integer)
  • TMPL_MAX_RELEASE_TIME: Maximum duration of a lock, that means release-time cannot be further away than this amount of seconds (Integer).

Local Account Variables

These are the local account variables that the main contract will save for each swap.

  • from (address): Swap locker address.
  • to (address): Swap redeemer address.
  • amount (integer): Amount of tokens to swap (The amount locked in the Escrow minus the fee).
  • release-time (Integer unix timestamp): Swap timeout. After this time, the locker is allowed to get their tokens back.
  • confirmed (integer): 0 if the swap was not confirmed or 1 otherwise.

Functions

Lock

Lock the tokens to swap and the fees to pay. You need to compile the Escrow contract first, replacing the template parameters with the proper values. Once compiled, the compiler will give you the logic signature file and the address of the account for that code. You can now make transactions from that account using the logic signature file.

Now that we are able to make transactions from the Escrow, we can make the lock. This needs multiple transactions in a single atomical group. For the first transaction we need to fund the escrow with algos, so it's able to pay the fees and OptIn to the contract, you can send funds from any account. The second transaction is the application OptIn call. The third makes the Escrow OptIn the asset (i.e. wAlgo) so it's able to make asset transactions. In Algorand you OptIn an asset by making an asset transaction to yourself. The last transaction is the asset transaction of the funds to the Escrow. We can inspect this transaction in the application call and know the amount to swap, this is why it is not a parameter in the application call.

Please note that all parameters in application calls in algorand are byte arrays. When passing integers, you cast the raw integer to a 8 byte array (Big Endian). Also the AssetSender field SHOULD NOT be used for normal Asset transactions, as it has a different meaning, Sender should be used instead.

  • Tx0 (The escrow fee fund)

    • Payment Transaction (pay)
    • Receiver: Escrow address
    • Amount: 600000 (0.6 Algos, rough estimate, can be fine tuned)
  • Tx1 (The application OptIn call):

    • Application Call tx
    • Application ID: Main contract ID
    • Sender: Escrow address
    • OnCompletion: OptIn
    • App Arguments:
      • arg0: integer: release-time
      • arg1: integer: confirmed (0 or 1)
      • arg2: integer: fee
    • Account Arguments:
      • acc0: locker
      • acc1: reedemer
  • Tx2 (The asset OptIn transaction):

    • AssetTransfer tx
    • XferAsset: Asset ID
    • Sender: Escrow address
    • AssetReceiver: Escrow address
    • AssetCloseTo: ZeroAddress
    • AssetAmount: 0
  • Tx3 (The asset fund transaction):

    • AssetTransfer tx
    • XferAsset: Asset ID
    • AssetReceiver: Escrow address
    • AssetCloseTo: ZeroAddress
    • AssetAmount: Amount in total including the fee

Confirm

This transaction confirms the swap for an escrow if it wasn't initially. Only if you are the one who initiated it. It's a simple application call:

  • Application Call tx
  • Application ID: Main contract ID
  • Sender: Locker
  • OnCompletion: NoOp
  • Account Arguments:
    • acc0: Escrow address

Redeem

This transaction atomical group will redeem the asset if the receiver exposes the secret correctly after the lock is confirmed. It needs these transactions:

  • Tx0 (The escrow fees for the remaining transactions)

    • Payment Transaction (pay)
    • Receiver: Escrow address
    • Amount: The sum of the fees for Tx1, Tx2 and Tx3
  • Tx1 (The application CloseOut call):

    • Application Call tx
    • Application ID: Main contract ID
    • Sender: Escrow address
    • OnCompletion: CloseOut
    • App Arguments:
      • arg0: str: secret
  • Tx2 (The asset redeem):

    • AssetTransfer tx
    • Sender: Escrow address
    • AssetReceiver: Reedemer
    • AssetCloseTo: Reedemer (This will send the remaining fee)
    • AssetAmount: Total amount minus the fee
  • Tx3 (The locker recovers their algos):

    • Payment Transaction (pay)
    • CloseRemainderTo: Locker Address
    • Amount: 0

Refund

Pretty much the same as before, but we send the funds to the locker and we don't send the secret.

  • Tx0 (The escrow fees for the remaining transactions)

    • Payment Transaction (pay)
    • Receiver: Escrow address
    • Amount: The sum of the fees for Tx1, Tx2 and Tx3
  • Tx1 (The application CloseOut call):

    • Application Call tx
    • Application ID: Main contract ID
    • Sender: Escrow address
    • OnCompletion: CloseOut
  • Tx2 (The asset refund):

    • AssetTransfer tx
    • Sender: Escrow address
    • AssetReceiver: Locker
    • AssetCloseTo: Reedemer (This will send the remaining fee)
    • AssetAmount: Total amount minus the fee
  • Tx3 (The locker account recovers its algos):

    • Payment Transaction (pay)
    • CloseRemainderTo: Locker Address
    • Amount: 0