Implement fees in the solana token bridge

Change-Id: I0bc29ced7e14c37294d0bde7ada173a90b5fcae4
This commit is contained in:
Hendrik Hofstadt 2021-08-20 09:51:55 +02:00
parent f42453be45
commit 2437a76ad7
5 changed files with 61 additions and 6 deletions

View File

@ -50,6 +50,7 @@ pub struct CompleteNative<'b> {
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
pub to: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
pub to_fees: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
pub custody: Mut<CustodyAccount<'b, { AccountState::Initialized }>>,
pub mint: Data<'b, SplMint, { AccountState::Initialized }>,
@ -98,6 +99,9 @@ pub fn complete_native(
if *accs.mint.info().key != accs.to.mint {
return Err(InvalidMint.into());
}
if *accs.mint.info().key != accs.to_fees.mint {
return Err(InvalidMint.into());
}
if *accs.mint.info().key != accs.custody.mint {
return Err(InvalidMint.into());
}
@ -121,10 +125,12 @@ pub fn complete_native(
accs.vaa.claim(ctx, accs.payer.key)?;
let mut amount = accs.vaa.amount.as_u64();
let mut fee = accs.vaa.fee.as_u64();
// Wormhole always caps transfers at 8 decimals; un-truncate if the local token has more
if accs.mint.decimals > 8 {
amount *= 10u64.pow((accs.mint.decimals - 8) as u32)
amount *= 10u64.pow((accs.mint.decimals - 8) as u32);
fee *= 10u64.pow((accs.mint.decimals - 8) as u32);
}
// Transfer tokens
@ -134,11 +140,20 @@ pub fn complete_native(
accs.to.info().key,
accs.custody_signer.key,
&[],
amount,
amount - fee,
)?;
invoke_seeded(&transfer_ix, ctx, &accs.custody_signer, None)?;
// TODO fee
// Transfer fees
let transfer_ix = spl_token::instruction::transfer(
&spl_token::id(),
accs.custody.info().key,
accs.to_fees.info().key,
accs.custody_signer.key,
&[],
fee,
)?;
invoke_seeded(&transfer_ix, ctx, &accs.custody_signer, None)?;
Ok(())
}
@ -154,6 +169,7 @@ pub struct CompleteWrapped<'b> {
pub chain_registration: Endpoint<'b, { AccountState::Initialized }>,
pub to: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
pub to_fees: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>,
pub mint: Mut<WrappedMint<'b, { AccountState::Initialized }>>,
pub mint_authority: MintSigner<'b>,
@ -202,6 +218,9 @@ pub fn complete_wrapped(
if *accs.mint.info().key != accs.to.mint {
return Err(InvalidMint.into());
}
if *accs.mint.info().key != accs.to_fees.mint {
return Err(InvalidMint.into());
}
// Verify VAA
if accs.vaa.to_chain != CHAIN_ID_SOLANA {
@ -218,11 +237,20 @@ pub fn complete_wrapped(
accs.to.info().key,
accs.mint_authority.key,
&[],
accs.vaa.amount.as_u64(),
accs.vaa.amount.as_u64() - accs.vaa.fee.as_u64(),
)?;
invoke_seeded(&mint_ix, ctx, &accs.mint_authority, None)?;
// TODO fee
// Mint fees
let mint_ix = spl_token::instruction::mint_to(
&spl_token::id(),
accs.mint.info().key,
accs.to_fees.info().key,
accs.mint_authority.key,
&[],
accs.vaa.fee.as_u64(),
)?;
invoke_seeded(&mint_ix, ctx, &accs.mint_authority, None)?;
Ok(())
}

View File

@ -155,6 +155,7 @@ pub fn transfer_native(
let trunc_divisor = 10u64.pow(8.max(accs.mint.decimals as u32) - 8);
// Truncate to 8 decimals
let amount: u64 = data.amount / trunc_divisor;
let fee: u64 = data.fee / trunc_divisor;
// Untruncate the amount to drop the remainder so we don't "burn" user's funds.
let amount_trunc: u64 = amount * trunc_divisor;
@ -181,7 +182,7 @@ pub fn transfer_native(
token_chain: 1,
to: data.target_address,
to_chain: data.target_chain,
fee: U256::from(data.fee),
fee: U256::from(fee),
};
let params = (
bridge::instruction::Instruction::PostMessage,

View File

@ -102,6 +102,7 @@ pub fn complete_native(
message_key: Pubkey,
vaa: PostVAAData,
to: Pubkey,
fee_recipient: Option<Pubkey>,
mint: Pubkey,
data: CompleteNativeData,
) -> solitaire::Result<Instruction> {
@ -129,6 +130,11 @@ pub fn complete_native(
claim_acc,
AccountMeta::new_readonly(endpoint, false),
AccountMeta::new(to, false),
if let Some(fee_r) = fee_recipient {
AccountMeta::new(fee_r, false)
} else {
AccountMeta::new(to, false)
},
AccountMeta::new(custody_key, false),
AccountMeta::new_readonly(mint, false),
AccountMeta::new_readonly(custody_signer_key, false),
@ -151,6 +157,7 @@ pub fn complete_wrapped(
vaa: PostVAAData,
payload: PayloadTransfer,
to: Pubkey,
fee_recipient: Option<Pubkey>,
data: CompleteWrappedData,
) -> solitaire::Result<Instruction> {
let config_key = ConfigAccount::<'_, { AccountState::Uninitialized }>::key(None, &program_id);
@ -180,6 +187,11 @@ pub fn complete_wrapped(
claim_acc,
AccountMeta::new_readonly(endpoint, false),
AccountMeta::new(to, false),
if let Some(fee_r) = fee_recipient {
AccountMeta::new(fee_r, false)
} else {
AccountMeta::new(to, false)
},
AccountMeta::new(mint_key, false),
AccountMeta::new_readonly(mint_authority_key, false),
// Dependencies

View File

@ -170,6 +170,7 @@ pub fn complete_transfer_native_ix(
bridge_id: String,
payer: String,
vaa: Vec<u8>,
fee_recipient: Option<String>,
) -> JsValue {
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
let bridge_id = Pubkey::from_str(bridge_id.as_str()).unwrap();
@ -201,6 +202,11 @@ pub fn complete_transfer_native_ix(
message_key,
post_vaa_data,
Pubkey::new(&payload.to[..]),
if let Some(fee_r) = fee_recipient {
Some(Pubkey::from_str(fee_r.as_str()).unwrap())
} else {
None
},
Pubkey::new(&payload.token_address),
CompleteNativeData {},
)
@ -215,6 +221,7 @@ pub fn complete_transfer_wrapped_ix(
bridge_id: String,
payer: String,
vaa: Vec<u8>,
fee_recipient: Option<String>,
) -> JsValue {
let program_id = Pubkey::from_str(program_id.as_str()).unwrap();
let bridge_id = Pubkey::from_str(bridge_id.as_str()).unwrap();
@ -247,6 +254,11 @@ pub fn complete_transfer_wrapped_ix(
post_vaa_data,
payload.clone(),
Pubkey::new(&payload.to),
if let Some(fee_r) = fee_recipient {
Some(Pubkey::from_str(fee_r.as_str()).unwrap())
} else {
None
},
CompleteWrappedData {},
)
.unwrap();

View File

@ -434,6 +434,7 @@ mod helpers {
*message_acc,
vaa,
Pubkey::new(&payload.to[..]),
None,
Pubkey::new(&payload.token_address[..]),
CompleteNativeData {},
)
@ -471,6 +472,7 @@ mod helpers {
vaa,
payload,
to,
None,
CompleteWrappedData {},
)
.expect("Could not create Complete Wrapped instruction");