Skip to content

Repository for AVM-compatible smart contracts for use by the Cross-Chain Transfer Protocol

License

Notifications You must be signed in to change notification settings

nullun/avm-cctp-contracts

Repository files navigation

avm-cctp-contracts

About

This repository contains AVM compatible smart contracts written in TEALScript for the Cross-Chain Transfer Protocol (CCTP).

The code was heavily inspired by the EVM smart contracts, and many of the comments have been copied over verbatim. Which is why they might not make much sense on Algorand. Further work is needed to tidy up the contracts and document how they operate.

Whilst the contracts function, they have not been thoroughly tested or audited in any way. Do not blindly use this in production!

How it works

Various design decisions were made to get this to work on the AVM. Below is a non-comprehensive list of some of the bigger differences.

  • ASAs cannot be burnt. Therefore the burning mechanism on the AVM relies on sending the asset to the reserve address, removing it from circulation. This works well for assets such as USDC, who already have procedures in place to withdraw-from and deposit-to their reserve address.
  • Redeeming an asset on the AVM smart contracts requires a single application call transaction along with a small payment of 0.0073 Algo to cover the MBR increase for storing the nonce. All resources needed for using the application are included in a single application call.
  • To prevent minting of assets multiple times, the source domain + nonce is stored as a box (key) for each successful mint. This was the cheapest and simplest solution I could come up with, which requires zero maintenance from the application owner.
  • Signature verification is done using ecdsa_pk_recover and comparing it to a list (box) of enabledAttesters. Each use of the ecdsa_pk_recover opcode requires over 2,000 opcode budget and so we utilise the "OpUp" application deploy-n-destroy pattern. This increases the minting cost by approximately 0.003 Algo per signature. (At the time of writing, Ethereum requires a signature threshold of 2 out of 2 possible enabled attesters).

Build

To install dependencies:

bun install

To compile contracts:

bunx tealscript src/*.algo.ts dist

Test

Steps to test on dual AVM chains.

Summary

  1. Deploy contracts
  2. Fund accounts
    1. User needs FakeUSDC1 to burn
    2. Both Token Minters need their respective assets
  3. Make sure a CCTP attestation service is running
  4. Run bun index.ts to simulate a CCTP transfer

Detailed

  1. Create Assets
    1. [AVM1] Create ASA with a valid reserve address
    2. [AVM2] Create ASA with a valid reserve address
  2. Deploy Contracts
    1. [AVM1] Deploy MessageTransmitter
    2. [AVM2] Deploy MessageTransmitter
    3. [AVM1] Deploy TokenMessenger
    4. [AVM2] Deploy TokenMessenger
    5. [AVM1] Deploy TokenMinter
    6. [AVM2] Deploy TokenMinter
  3. Configure MessageTransmitter
    1. [AVM1] Send MBR to MessageTransmitter for enabledAttester box
    2. [AVM1] Add Attester to MessageTransmitter (enableAttester)
    3. [AVM2] Send MBR to MessageTransmitter for enabledAttester box
    4. [AVM2] Add Attester to MessageTransmitter (enableAttester)
  4. Configure TokenMessenger
    1. [AVM1] Send MBR to TokenMessenger for remoteTokenMessengers box
    2. [AVM1] Add remote TokenMessenger to TokenMessenger (addRemoteTokenMessenger)
    3. [AVM2] Send MBR to TokenMessenger for remoteTokenMessengers box
    4. [AVM2] Add remote TokenMessenger to TokenMessenger (addRemoteTokenMessenger)
    5. [AVM1] Add local TokenMinter to TokenMessenger (addLocalMinter)
    6. [AVM2] Add local TokenMinter to TokenMessenger (addLocalMinter)
  5. Configure TokenMinter
    1. [AVM1] Send MBR to TokenMinter for holding hash(remoteDomain+assetId) box
    2. [AVM1] Link remote domain + local token to remote token in TokenMinter (linkTokenPair)
    3. [AVM2] Send MBR to TokenMinter for holding hash(remoteDomain+assetId) box
    4. [AVM2] Link remote domain + local token to remote token in TokenMinter (linkTokenPair)
    5. [AVM1] Set max burn amount per message for asset in TokenMinter (setMaxBurnAmountPerMessage)
    6. [AVM2] Set max burn amount per message for asset in TokenMinter (setMaxBurnAmountPerMessage)
    7. [AVM1] Add local TokenMessenger to TokenMinter (addLocalTokenMessenger)
    8. [AVM2] Add local TokenMessenger to TokenMinter (addLocalTokenMessenger)

Useful transactions

depositForBurn

goal asset send \
    --assetid $ASSET1 \
    --from $YOUR_ADDRESS \
    --to $TOKEN_MINTER_ADDR \
    --amount 1000000 \
    -o burn.txn

goal app method \
    --app-id $TOKEN_MESSENGER \
    --from $YOUR_ADDRESS \
    --method "depositForBurn(axfer,uint32,byte[32],asset)uint64" \
    --arg burn.txn \
    --arg 9                                                # Destination Domain \
    --arg '"i4C45SLboL5UDstqo37uKS1WzqqtOSlp+3COLk1LcEo="' # Mint Recipient \
    --arg $ASSET1                                          # Just the ID, not a reference \
    --box b64:AAAACQ==                                     # Destination Domain (lookup remote token messenger) \
    --foreign-app $TOKEN_MINTER                            # TokenMinter AppID \
    --fee 4000 \
    --box $TOKEN_MINTER,b64:AAAAAAAAA+w=                   # TokenMinter AssetID (for checking burn limit) \
    --app-account $ASSET1_RESERVE_ADDRESS \
    --foreign-app $MessageTransmitter

sign message

Please first open sign_message.ts and add the attester private key and log from the depositForBurn.

bun sign_message.ts

receiveMessage

goal clerk send \
    --from $YOUR_ADDRESS \
    --to $MESSAGE_TRANSMITTER_ADDR \
    --amount 7300 \
    -o mbr.txn

goal app method \
    --app-id $MESSAGE_TRANSMITTER \
    --from $YOUR_ADDRESS \
    --method "receiveMessage(pay,byte[],byte[])bool" \
    --arg mbr.txn \
    --arg '"AAAAAAAAAAUAAAAJAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+yLgLjlItugvlQOy2qjfu4pLVbOqq05KWn7cI4uTUtwSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD0JAi4C45SLboL5UDstqo37uKS1WzqqtOSlp+3COLk1LcEo="' \
    --arg '"32E8j2Rk+GJBIlYh7mm2uyQj3w77I7HOLXednfvrgTZHL4BK85nwurDyYsKRXDV5eRIXhNTNRiWtZ+R548Sb7hs="' \
    --fee 12000 \
    --box str:enabledAttesters \
    --box b64:AAAABQAAAAAAAAAB \
    --foreign-app $TOKEN_MESSENGER \
    --box 1014,b64:AAAABQ== \
    --foreign-app $TOKEN_MINTER \
    --box 1015,b64:7IC93Vlr7wCjQrIaXKmNuUycqU+f8OdQs3EZGzxuoNw= \
    --foreign-asset $ASSET2

About

Repository for AVM-compatible smart contracts for use by the Cross-Chain Transfer Protocol

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published