@debridge-finance/solana-contracts-client
v4.1.4
Published
[Docs](docs/README.md)
Downloads
3,691
Readme
Client init
Since js doesn't support async constructors we have to initialize client object with const client = new DeBridgeSolanaClient()
and then wait until it initializes (await client.init()
) - loads program state, etc...
After initialization we can request data from blockchain and build transactions
How to wrap Sol->WSol (SPL-Sol)
We can't send native SOL tokens, we need to wrap them first into SPL-token form (SystemProgram.createAccount
+ SystemProgram.transfer
native sol to created account + TokenProgram.InitializeAccount
to convert system account into token account (SPL-wallet)). If we don't want to create new wallet we can call SystemProgram.transfer
and then TokenProgram.SyncNative
to convert transferred Sols into SPL-Sol
How to send token from Solana to other blockchain?
- Check if user's associated wallet exists and user have ehough tokens. We can get all user's wallets with
getAllWalletsWithBalances
- Check if chain is supported - we can't send from Solana to unsupported chains, hence
chainSupportInfo
must exist and be inSupported
state, seegetChainSupportInfoSafe
for details - Check if bridge exists (SPL-tokens are sent via Send bridge, deAssets are sent via Mint bridge which 100% exists) and in Working state - if bridge doesn't exist we can't send tokens and we need to init bridge first (see bridge initialization->send). We can check if bridge exists with getBridgeByDeBridgeId
- [Optional] If we want to pay fee with asset we're sending, we need to set
useAssetFee
flag to true and check if bridgeFeeInfo exists usingisBridgeFeeInfoInitialized
. If bridgeFeeInfo->assetChainFee not exists we can't pay fee with assets and we also can't init bridgeFeeInfo. - [Optional] If we want to pass some additional data (external call data) we have two options - set SEND_HASHED flag and pass external call data off-chain (saves gas but automatic execution is unavailable) or save external call data into special Solana account (ExternalCallStorage) associated with send transaction
- ExtCallShortcut flow - we need to pass external call shortcut (
keccak256(ext call data)
) and flags with 4th bit (8) set to send->submissionParams - ExtCallStorage flow - see externall call preparation section
- ExtCallShortcut flow - we need to pass external call shortcut (
- Send! If we have a discount we want to pass it into
send
instruction, else we need to pass speical no_discount account (butbuildSendInstruction
calculates all the accounts under the hood). We also need to specify which wallet we want to use (user may have multiple wallets associated with same token mint), execution fee is a reward for automatic claim in target chain
How to claim token from other blockchain to Solana
- Check if chain is supported - we can't claim from unsupported chains, hence
chainSupportInfo
must exist and be inSupported
state, seegetChainSupportInfoSafe
for details - Check if bridge exists -
getBridgeByDeBridgeId
(deAssets are claimed via Send bridge, assets are claimed via Mint) and in Working state - if bridge doesn't exist we can't send tokens and we need to init bridge first (see bridge initialization->mint). - Check if submission wasn't already claimed with
isSubmissionUsed
- Store confirmations from validators with
storeConfirmations
instruction (one transaction can store up to 6 signatures) which can be built withbuildStoreSignaturesTransaction
, this transactions can be signed and sent in a batch mode. - [Optional] If we have external call data we need to check if SEND_HASHED_FLAG is set. If flag is not set we need to fill ExternalCallStorage
- ExtCallStorage flow - see externall call preparation section
- All checks from steps 1,2 and 3 can be performed in automatic mode with function
checkClaimParams
- check if submission is not already claimed, check bridge balance, check chainSupportInfo and Bridge. - Claim! just call
claim
instruction built withbuildClaimTransaction
after all signatures were saved - this can be checked withisTransactionConfirmed
orgetConfirmationsCount
- [Optional] if external call exists, we need to execute it, we could execute them by calling
buildOptimalExecuteExternalCallTransaction
. This function tries to build tx with execution of as much as possible external instructions. Need to be called until external call is executed or fails to execute.
External call data preparation
Since solana's transaction size limit is 1232 bytes we can't store all external call data in single transaction, hence we need to split the data in chunks and send bunch of chunks in different transactions.
We need to call initExternalCallStorage
instruction (storageKey = external call shortcut - claim/extCallShortcut - send, external call length = external call data length, source chain id = source chain - claim/solana id - send) to allocate memory and fill first chunk. If external call data is larger than ~800 bytes, we need to initialize externall call storage and fill it with data calling extendExternalCallStorage
instruction buildExtendExternalCallStorageInstruction
.
Function prepareExtCallTransactions
splits data into chunks of optimal size and returns array of transactions to execute. First tx is initExternalCallStorage
, rest (optional) are extendExternalCallStorage
. initExternalCallStorage
allocates required memory space in blockchain and fills it with initial data chunk. Since we can't write data to not-yet-allocated memory we have to wait until first transaction is finalized and extCallStorage is allocated. After that we can send rest transactions in a batch mode and wait until Solana processes them. We can check if storage was filled correctly using isExtCallStorageCorrect
Bridge initialization
- Send bridge - to init send bridge we need to call
initializeSendBridge
instruction for SPL-token mint that we want to init -buildInitializeSendBridgeTransaction
. - Mint bridge - to init mint bridge we need to
storeConfirmations
for deploy info, wait until confirmations are saved and then callinitializeMintBridge
instruction -buildInitializeMintBridgeTransaction
Entities
- State - unique, contains oracles, required oracles, min confirmations, if protocol is active and other system information.
- Bridge (general info) - contains bridge state (working/paused), collected fee and other system information.
- Send bridge - assocated with token, contains amount of locked tokens, native SPL-token address and general bridge info
- Mint bridge - associated with token in outter chain and outer chain id, contains amount of minted tokens, source chain id, source token address and general bridge info
- ChainSupportInfo - associated with chain, contains State (supported/unsupported) of target chain and fixedFee/transferFee values (if values are None globalFixedFee/globalTransferFee will be used)
- BridgeFeeInfo - associated with bridge, contains assetChainFee option (None or value, if None asset chain fee is unsupported)
Claim flow (with ext call) with affected accounts (Assuming that submission wasn't claimed, bridge/state/chainSupportInfo exists)
| Action | Initialized accounts | Updated Accounts | Closed Accounts | Comments |
|--------|----------------------|------------------| ----------------|----------|
| storeConfirmations
| [confirmationStorage] | confirmationStorage | | store signatures into confirmationStorage, account is created if not exists yet |
|initExternalCallStorage
| externalCallStorage, externalCallMeta | | | allocate externall call storage, set externalCallMeta = accumulation
|
|updateExternalCallStorage
| | externalCallStorage, externalCallMeta| | fill external call storage with data, set externalCallMeta = accumulation
|
|claim
| submission, [stakingWallet], [payerWallet], [claimToWallet] | bridge, stakingWallet, payerWallet, claimToWallet | confirmationStorage | create submission account, close confirmation storage, set externalCallMeta state = execution
, update bridge locked/minted amount, move funds to/from wallets |
|executeExternalCall
| | externalCallMeta | externalCallStorage | set externalCallMeta = executed
, close external call storage |
Claim flow (without ext call) with affected accounts (Assuming that submission wasn't claimed, bridge/state/chainSupportInfo exists)
| Action | Initialized accounts | Updated Accounts | Closed Accounts | Comments |
|--------|----------------------|------------------| ----------------|----------|
| storeConfirmations
| [confirmationStorage] | confirmationStorage | | store signatures into confirmationStorage, account is created if not exists yet |
|claim
| submission, [stakingWallet], [payerWallet], [claimToWallet] | bridge, stakingWallet, payerWallet, claimToWallet | confirmationStorage | create submission account, close confirmation storage, update bridge locked/minted amount, move funds to/from wallets |