-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix errors found in the TBRv3 Solana Audit #105
base: main
Are you sure you want to change the base?
Conversation
feli-xlabs
commented
Jan 2, 2025
- Allow to create accounts by hand even if they're squatted.
- Refactor the program ownership transfer so that we only need the new owner's signature when accepting the transfer.
- Check both the chain ID and the peer address in case of an inbound transfer
… so that when the new owner accepts the transfer, there is no need for the previous owner's signature.
0886d29
to
1fb1484
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only comments/nits, nothing that's really important.
const ixs = []; | ||
|
||
ixs.push(this.registerPeer(signer, chain, peerAddress)); | ||
if (config.maxGasDropoffMicroToken !== 0) { | ||
ixs.push(this.updateMaxGasDropoff(signer, chain, config.maxGasDropoffMicroToken)); | ||
} | ||
ixs.push(this.updateBaseFee(signer, chain, config.relayerFeeMicroUsd)); | ||
ixs.push(this.setPauseForOutboundTransfers(signer, chain, config.pausedOutboundTransfers)); | ||
|
||
return Promise.all(ixs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const ixs = []; | |
ixs.push(this.registerPeer(signer, chain, peerAddress)); | |
if (config.maxGasDropoffMicroToken !== 0) { | |
ixs.push(this.updateMaxGasDropoff(signer, chain, config.maxGasDropoffMicroToken)); | |
} | |
ixs.push(this.updateBaseFee(signer, chain, config.relayerFeeMicroUsd)); | |
ixs.push(this.setPauseForOutboundTransfers(signer, chain, config.pausedOutboundTransfers)); | |
return Promise.all(ixs); | |
return Promise.all([ | |
this.registerPeer(signer, chain, peerAddress), | |
...(config.maxGasDropoffMicroToken !== 0 | |
? [this.updateMaxGasDropoff(signer, chain, config.maxGasDropoffMicroToken))] | |
: [] | |
), | |
this.updateBaseFee(signer, chain, config.relayerFeeMicroUsd), | |
this.setPauseForOutboundTransfers(signer, chain, config.pausedOutboundTransfers) | |
]); |
nit/style suggestion originally mentioned on slack
@@ -144,6 +144,8 @@ pub fn complete_transfer( | |||
} = *ctx.accounts.vaa.message().data(); | |||
let gas_dropoff_amount = denormalize_dropoff_to_lamports(gas_dropoff_amount); | |||
|
|||
let _x = ctx.accounts.vaa.message(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like a leftover
@@ -116,7 +116,7 @@ pub struct OutboundTransfer<'info> { | |||
/// CHECK: Token Bridge emitter. | |||
pub token_bridge_emitter: UncheckedAccount<'info>, | |||
|
|||
/// CHECK: Token Bridge sequence. | |||
/// CHECK: Token Bridge sequence. Mutable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems redundant and also not in line with e.g. the fee_recipient comment above, which is also mutable but isn't commented as such either.
let total_fees_mwei = (|| { | ||
let evm_transaction_fee_mwei = config | ||
.evm_transaction_gas | ||
.checked_mul(u64::from(oracle_evm_prices.gas_price))?; | ||
let evm_tx_size_fee_mwei = config | ||
.evm_transaction_size | ||
.checked_mul(u64::from(oracle_evm_prices.price_per_byte))?; | ||
let dropoff_mwei = u64::from(dropoff_amount_micro).checked_mul(MWEI_PER_MICRO_ETH)?; | ||
|
||
evm_transaction_fee_mwei | ||
.checked_add(evm_tx_size_fee_mwei)? | ||
.checked_add(dropoff_mwei) | ||
})() | ||
.ok_or(TokenBridgeRelayerError::Overflow)?; | ||
|
||
// μusd = Mwei * μusd/Token / Mwei/Token + μusd) | ||
let total_fees_micro_usd = u64::try_from( | ||
u128::from(total_fees_mwei) * u128::from(oracle_evm_prices.gas_token_price) / MWEI_PER_ETH, | ||
) | ||
.expect("Overflow") | ||
+ u64::from(chain_config.relayer_fee_micro_usd); | ||
.map_err(|_| TokenBridgeRelayerError::Overflow)? | ||
.checked_add(u64::from(chain_config.relayer_fee_micro_usd)) | ||
.ok_or(TokenBridgeRelayerError::Overflow)?; | ||
|
||
// lamports/SOL * μusd / μusd/SOL | ||
Ok((LAMPORTS_PER_SOL * total_fees_micro_usd) / oracle_config.sol_price) | ||
let fee = total_fees_micro_usd | ||
.checked_mul(LAMPORTS_PER_SOL) | ||
.map(|sol| sol / oracle_config.sol_price) | ||
.ok_or(TokenBridgeRelayerError::Overflow)?; | ||
|
||
Ok(fee) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see where the motivation for the custom type with a single, simple overflow check at the end that you mentioned came from. Only a mother can love this code.
@@ -18,6 +18,9 @@ pub mod constant { | |||
|
|||
#[constant] | |||
pub const SEED_PREFIX_TEMPORARY: &[u8] = b"tmp"; | |||
|
|||
#[constant] | |||
pub const SEED_PREFIX_UPGRADE_LOCK: &[u8] = b"upgrade lock"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub const SEED_PREFIX_UPGRADE_LOCK: &[u8] = b"upgrade lock"; | |
pub const SEED_PREFIX_UPGRADE_LOCK: &[u8] = b"upgrade_lock"; |
I think we canonically use underscore instead of a plain space in seed prefixes
userTokenAccount: tokenAccount.publicKey, | ||
transferredAmount, | ||
gasDropoffAmount, | ||
maxFeeLamports: 100_000_000n, // 0.1SOL max |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably use LAMPORT_PER_SOL/10
rather than use a comment (and same for the other values)
type Tuple<T, N extends number, R extends T[] = []> = R['length'] extends N | ||
? R | ||
: Tuple<T, N, [T, ...R]>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should (probably) use the corresponding type from the SDKv2 instead (it's very marginal though).
several: <N extends number>(amount: N): Tuple<Keypair, N> => | ||
Array.from({ length: amount }).map(Keypair.generate) as Tuple<Keypair, N>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same considerations as above.
several: <N extends number>( | ||
amount: number, | ||
ethereum?: 'ethereum', | ||
): Tuple<UniversalAddress, N> => | ||
Array.from({ length: amount }).map(() => this.universalAddress.generate(ethereum)) as Tuple< | ||
UniversalAddress, | ||
N | ||
>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same considerations as above.
several: <N extends number>(amount: number): Tuple<PublicKey, N> => | ||
Array.from({ length: amount }).map(PublicKey.unique) as Tuple<PublicKey, N>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason not to just make this an optional parameter of generate
? also, N should be const
here and amount
seems like a suboptimal choice of name since it is more associated with tokens. count
would likely be better.