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 meansrelease-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 thefee
). -
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)
- Payment Transaction (
-
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
- arg0: integer:
- Account Arguments:
- acc0:
locker
- acc1:
reedemer
- acc0:
-
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
- Payment Transaction (
-
Tx1 (The application
CloseOut
call):- Application Call tx
- Application ID: Main contract ID
- Sender: Escrow address
- OnCompletion:
CloseOut
- App Arguments:
- arg0: str:
secret
- arg0: str:
-
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
- Payment Transaction (
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
- Payment Transaction (
-
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
- Payment Transaction (