added solana readmd
This commit is contained in:
parent
57704ed023
commit
2df20cceaf
|
@ -0,0 +1,45 @@
|
||||||
|
Scenario: User from Chain A wants to swap Token A for Token B on Chain B.
|
||||||
|
|
||||||
|
Step 1: User transfers Token A to Native Swap through the token bridge
|
||||||
|
Step 2: Native Swap redeems the transfer from the token bridge and takes custody of the wrapped-Token A
|
||||||
|
Step 3a: for "NoSwap", Native Swap sends wrapped-Token A to recipient wallet on Chain B.
|
||||||
|
Step 3b: for "WithSwap", Native Swap swaps wrapped-Token A for Token B and sends Token B to recipient wallet on Chain B
|
||||||
|
|
||||||
|
Instruction::CompleteTransfer
|
||||||
|
Description: redeems wrapped tokens from the token bridge ATA, transfers them to the NativeSwap ATA.
|
||||||
|
Extremely similar to CompleteWrappedWithPayload struct in the token bridge sdk except, instead of the user redeeming the transfer, NativeSwap redeems it.
|
||||||
|
|
||||||
|
Instruction::CompleteNoSwap
|
||||||
|
Description: transfers wrapped tokens from NativeSwap ATA to user's ATA
|
||||||
|
|
||||||
|
### Running
|
||||||
|
Set you id.json to your private key
|
||||||
|
```
|
||||||
|
~/.config/solana/id.json
|
||||||
|
```
|
||||||
|
Build the cargo
|
||||||
|
```
|
||||||
|
EMITTER_ADDRESS=EMITTER_ADDRESS BRIDGE_ADDRESS=BRIDGE_ADDRESS TOKEN_BRIDGE_ADDRESS=TOKEN_BRIDGE_ADDRESS cargo build-bpf
|
||||||
|
```
|
||||||
|
Write the program byte code into a buffer address
|
||||||
|
```
|
||||||
|
solana program write-buffer target/deploy/wormhole_nativeswap.so -u d
|
||||||
|
```
|
||||||
|
Take the buffer address & Deploy the contract
|
||||||
|
```
|
||||||
|
solana program deploy --program-id PROGRAM_ID --buffer BUFFER -u d
|
||||||
|
>in testnet (solana devnet), PROGRAM_ID=92XVWWdN47dL38HLZ277rdRJh7RUG2ikmiBRoUGrKXif
|
||||||
|
```
|
||||||
|
Compile the wasm bindings
|
||||||
|
```
|
||||||
|
EMITTER_ADDRESS="11111111111111111111111111111115" BRIDGE_ADDRESS="3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5" TOKEN_BRIDGE_ADDRESS="DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe" wasm-pack build --target nodejs -d nodejs -- --features wasm
|
||||||
|
```
|
||||||
|
Now the wasm node package is ready to use.
|
||||||
|
```
|
||||||
|
cd test
|
||||||
|
MNEMONIC=PRIVATE_KEY node index.js
|
||||||
|
```
|
||||||
|
transfer_ix: the transfer instruction to redeem the tokens from the token bridge and transfer them to NativeSwap. you have to submit a tokenTransfer VAA where the recipient is the custody address
|
||||||
|
|
||||||
|
no_swap_ix: the transfer instruction to move the tokens from NativeSwap to the recipients wallet.
|
||||||
|
|
|
@ -32,6 +32,9 @@ use solitaire::{
|
||||||
*,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// have to create custom config account for the token bridge b/c the default ConfigAccount in solana/modules/token_bridge/program/src/accounts.rs
|
||||||
|
// is a derived account and assumes the program id is the ExecutionContext,
|
||||||
|
// which is normally the token bridge... but in this case would be NativeSwap.
|
||||||
pub type TokenBridgeConfigAccount<'b, const STATE: AccountState> = Data<'b, Config, { STATE }>;
|
pub type TokenBridgeConfigAccount<'b, const STATE: AccountState> = Data<'b, Config, { STATE }>;
|
||||||
|
|
||||||
pub struct TokenBridgeConfigAccountDerivationData {
|
pub struct TokenBridgeConfigAccountDerivationData {
|
||||||
|
@ -49,7 +52,8 @@ impl<'b, const STATE: AccountState> Seeded<&TokenBridgeConfigAccountDerivationDa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type TokenBridgeMintSigner<'b> = Info<'b>;
|
//Info is short alias for AccountInfo from solana programs
|
||||||
|
pub type TokenBridgeMintSigner<'b> = Info<'b>;
|
||||||
|
|
||||||
pub struct TokenBridgeMintSignerDerivationData {
|
pub struct TokenBridgeMintSignerDerivationData {
|
||||||
pub token_bridge: Pubkey,
|
pub token_bridge: Pubkey,
|
||||||
|
@ -66,6 +70,27 @@ impl<'b> Seeded<&TokenBridgeMintSignerDerivationData>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[derive(FromAccounts)]
|
||||||
|
pub struct CompleteWrappedWithPayload<'b> {
|
||||||
|
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
||||||
|
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
|
||||||
|
|
||||||
|
// Signed message for the transfer
|
||||||
|
pub vaa: ClaimableVAA<'b, PayloadTransferWithPayload>,
|
||||||
|
|
||||||
|
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||||
|
|
||||||
|
pub to: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub to_owner: MaybeMut<Signer<Info<'b>>>,
|
||||||
|
pub to_fees: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
|
||||||
|
pub mint: Mut<WrappedMint<'b, { AccountState::Initialized }>>,
|
||||||
|
pub wrapped_meta: WrappedTokenMeta<'b, { AccountState::Initialized }>,
|
||||||
|
|
||||||
|
pub mint_authority: MintSigner<'b>,
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#[derive(FromAccounts)]
|
#[derive(FromAccounts)]
|
||||||
pub struct CompleteTransfer<'b> {
|
pub struct CompleteTransfer<'b> {
|
||||||
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
pub payer: Mut<Signer<AccountInfo<'b>>>,
|
||||||
|
@ -76,15 +101,16 @@ pub struct CompleteTransfer<'b> {
|
||||||
// Above includes claim account
|
// Above includes claim account
|
||||||
|
|
||||||
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
|
||||||
|
// custody == Native Swap ATA
|
||||||
pub custody: Mut<CustodyAccount<'b, { AccountState::MaybeInitialized }>>,
|
pub custody: Mut<CustodyAccount<'b, { AccountState::MaybeInitialized }>>,
|
||||||
|
// custody signer == PDA of Native Swap Program ID
|
||||||
pub custody_signer: CustodySigner<'b>,
|
pub custody_signer: CustodySigner<'b>,
|
||||||
pub to_fees: Mut<Data<'b, SplAccount, { AccountState::MaybeInitialized }>>,
|
pub to_fees: Mut<Data<'b, SplAccount, { AccountState::MaybeInitialized }>>,
|
||||||
pub mint: Mut<WrappedMint<'b, { AccountState::Initialized }>>,
|
pub mint: Mut<WrappedMint<'b, { AccountState::Initialized }>>,
|
||||||
pub wrapped_meta: WrappedTokenMeta<'b, { AccountState::Initialized }>,
|
pub wrapped_meta: WrappedTokenMeta<'b, { AccountState::Initialized }>,
|
||||||
|
|
||||||
pub mint_authority: TokenBridgeMintSigner<'b>,
|
pub mint_authority: TokenBridgeMintSigner<'b>,
|
||||||
pub token_bridge: Info<'b>,
|
pub token_bridge: Info<'b>, //<-- added for derived config, endpoint, & wrapped metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&CompleteTransfer<'a>> for EndpointDerivationData {
|
impl<'a> From<&CompleteTransfer<'a>> for EndpointDerivationData {
|
||||||
|
@ -105,6 +131,8 @@ impl<'a> From<&CompleteTransfer<'a>> for WrappedDerivationData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// have to define implementations for the derived data similar to CompleteWrappedWithPayload
|
||||||
|
|
||||||
impl<'a> From<&CompleteTransfer<'a>> for CustodyAccountDerivationData {
|
impl<'a> From<&CompleteTransfer<'a>> for CustodyAccountDerivationData {
|
||||||
fn from(accs: &CompleteTransfer<'a>) -> Self {
|
fn from(accs: &CompleteTransfer<'a>) -> Self {
|
||||||
CustodyAccountDerivationData {
|
CustodyAccountDerivationData {
|
||||||
|
@ -125,15 +153,19 @@ pub fn complete_transfer(
|
||||||
_data: CompleteTransferData,
|
_data: CompleteTransferData,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
|
||||||
|
msg!("program id: {:?}", ctx.program_id);
|
||||||
|
msg!("accounts: {:?}", ctx.accounts);
|
||||||
|
// core bridge
|
||||||
let bridge_id = ctx.accounts[14].info().key;
|
let bridge_id = ctx.accounts[14].info().key;
|
||||||
|
//where the payload/postedVaa is being stored
|
||||||
let message_key = ctx.accounts[2].info().key;
|
let message_key = ctx.accounts[2].info().key;
|
||||||
msg!("bridge_id: {:?}", bridge_id);
|
|
||||||
msg!("message_key: {:?}", message_key);
|
// Verify that the custody account is a ATA of custody owner aka native swap
|
||||||
// Verify that the custody account is derived correctly
|
|
||||||
let derivation_data: CustodyAccountDerivationData = (&*accs).into();
|
let derivation_data: CustodyAccountDerivationData = (&*accs).into();
|
||||||
accs.custody
|
accs.custody
|
||||||
.verify_derivation(ctx.program_id, &derivation_data)?;
|
.verify_derivation(ctx.program_id, &derivation_data)?;
|
||||||
|
|
||||||
|
// if the ATA of the wrapped token belonging to NativeSwap is not created, create it
|
||||||
if !accs.custody.is_initialized() {
|
if !accs.custody.is_initialized() {
|
||||||
accs.custody
|
accs.custody
|
||||||
.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
|
.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
|
||||||
|
@ -149,7 +181,8 @@ pub fn complete_transfer(
|
||||||
|
|
||||||
// see https://github.com/certusone/wormhole/blob/2e24f11fa045ac8460347d9796a4ecdb7931a154/solana/modules/token_bridge/program/src/instructions.rs#L312-L338
|
// see https://github.com/certusone/wormhole/blob/2e24f11fa045ac8460347d9796a4ecdb7931a154/solana/modules/token_bridge/program/src/instructions.rs#L312-L338
|
||||||
// TODO: maybe there's a better way to rebuild this off our list of accounts which should be nearly compatible
|
// TODO: maybe there's a better way to rebuild this off our list of accounts which should be nearly compatible
|
||||||
|
|
||||||
|
// transfer the wrapped token from the token bridge ATA to the NativeSwap ATA
|
||||||
let transfer_ix = Instruction {
|
let transfer_ix = Instruction {
|
||||||
program_id: *accs.token_bridge.info().key,
|
program_id: *accs.token_bridge.info().key,
|
||||||
accounts: vec![
|
accounts: vec![
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const { uint8ArrayToNative } = require("@certusone/wormhole-sdk");
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const PAYLOAD_1_VAA =
|
const PAYLOAD_1_VAA =
|
||||||
"01000000000100339c0d030b927eda9cb7ee53d266cbdc6d8f2a70a2a8031952a3a19ee3963d77030dfa8d70c134ef577f9db119cd606bf82ad593f6bb5addfc57f33e741e7e6201624b367c636d0000000b000000000000000000000000d11de1f930ea1f7dd0290fe3a2e35b9c91aefb37000000000000000c010100000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000337610d27c682e347c9cd60bd4b3b107c9d34ddd000400000000000000000000000012345756e90eba0c357d6ea5d537a179f9d6d0b000040000000000000000000000000000000000000000000000000000000000000000";
|
"01000000000100339c0d030b927eda9cb7ee53d266cbdc6d8f2a70a2a8031952a3a19ee3963d77030dfa8d70c134ef577f9db119cd606bf82ad593f6bb5addfc57f33e741e7e6201624b367c636d0000000b000000000000000000000000d11de1f930ea1f7dd0290fe3a2e35b9c91aefb37000000000000000c010100000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000337610d27c682e347c9cd60bd4b3b107c9d34ddd000400000000000000000000000012345756e90eba0c357d6ea5d537a179f9d6d0b000040000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
@ -53,6 +55,7 @@
|
||||||
sdk.hexToUint8Array(PAYLOAD_3_VAA_TO_SOLANA_WITH_CUSTODY_SIGNER2)
|
sdk.hexToUint8Array(PAYLOAD_3_VAA_TO_SOLANA_WITH_CUSTODY_SIGNER2)
|
||||||
);
|
);
|
||||||
console.log(transfer_ix_json);
|
console.log(transfer_ix_json);
|
||||||
|
console.log("Program Id:", sdk.uint8ArrayToNative(transfer_ix_json.program_id, 1))
|
||||||
console.log(
|
console.log(
|
||||||
transfer_ix_json.accounts.map(({ pubkey, is_signer, is_writable }) => [
|
transfer_ix_json.accounts.map(({ pubkey, is_signer, is_writable }) => [
|
||||||
sdk.hexToNativeString(
|
sdk.hexToNativeString(
|
||||||
|
@ -84,7 +87,6 @@
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const transfer_ix = sdk.ixFromRust(transfer_ix_json);
|
const transfer_ix = sdk.ixFromRust(transfer_ix_json);
|
||||||
const no_swap_ix = sdk.ixFromRust(no_swap_ix_json);
|
const no_swap_ix = sdk.ixFromRust(no_swap_ix_json);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue