Skip to content
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

Solana/sdk set evm cost initialize #116

Merged
merged 8 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion deployment/config/localnet/solana-tbr-init.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
"11111111111111111111111111111111",
"11111111111111111111111111111111",
"11111111111111111111111111111111"
]
],
"evmRelayGas": "400000",
"evmRelayTxSize": "1211"
}
4 changes: 3 additions & 1 deletion deployment/config/mainnet/solana-tbr-init.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
"11111111111111111111111111111111",
"11111111111111111111111111111111",
"11111111111111111111111111111111"
]
],
"evmRelayGas": "400000",
"evmRelayTxSize": "1211"
}
4 changes: 3 additions & 1 deletion deployment/config/testnet/solana-tbr-init.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"owner": "C4g4fRKT1xF6tFvo8QoPccVGsrzFgbHZnMRXfsSNQ8dm",
"feeRecipient": "hiUN9rS9VTPVGYc71Vf2d6iyFLvsQaSsqWhxydqdaZf",
"admins": []
"admins": [],
"evmRelayGas": "400000",
"evmRelayTxSize": "1211"
}
2 changes: 2 additions & 0 deletions deployment/helpers/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export type SolanaTbrInitParams = {
owner: string;
feeRecipient: string;
admins: string[];
evmRelayGas: string;
evmRelayTxSize: string;
}

export type ContractsJson = Record<string, Deployment[]>;
Expand Down
3 changes: 3 additions & 0 deletions deployment/helpers/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ export function getConnection(chain: SolanaChainInfo) {
return connection;
}

/**
* @todo Add priority fee instruction when configured to do so.
*/
export async function ledgerSignAndSend(connection: Connection, instructions: TransactionInstruction[], signers: Keypair[]) {
const deployerSigner = await getSigner();

Expand Down
25 changes: 16 additions & 9 deletions deployment/solana/initialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { loadSolanaTbrInitParams } from '../helpers/env.js';

const initializeSolanaTbr: SolanaScriptCb = async function (
chain,
// signer,
signer,
// log,
) {
const connection = getConnection(chain);
Expand All @@ -15,20 +15,27 @@ const initializeSolanaTbr: SolanaScriptCb = async function (
const tbrInitParams = loadSolanaTbrInitParams();

if (!tbrInitParams.owner) {
throw new Error ("initialization parameters: owner address is required.")
throw new Error ("initialization parameters: owner address is required.");
}

if (!tbrInitParams.feeRecipient) {
throw new Error ("initialization parameters: feeRecipient address is required.")
throw new Error ("initialization parameters: feeRecipient address is required.");
}

const initializeIx = await tbr.initialize({
owner: new PublicKey(tbrInitParams.owner),
feeRecipient: new PublicKey(tbrInitParams.feeRecipient),
admins: tbrInitParams.admins.map((adminKey) => new PublicKey(adminKey)),
});
const deployerPubkey = new PublicKey(await signer.getAddress());

await ledgerSignAndSend(connection, [initializeIx], []);
const initializeIxs = await tbr.initialize(
deployerPubkey,
{
owner: new PublicKey(tbrInitParams.owner),
feeRecipient: new PublicKey(tbrInitParams.feeRecipient),
admins: tbrInitParams.admins.map((adminKey) => new PublicKey(adminKey)),
},
BigInt(tbrInitParams.evmRelayGas),
BigInt(tbrInitParams.evmRelayTxSize)
);

await ledgerSignAndSend(connection, initializeIxs, []);
}

runOnSolana('initialize-tbr', initializeSolanaTbr).catch((e) => {
Expand Down
3 changes: 1 addition & 2 deletions evm/src/assets/TbrUser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ uint32 constant SOLANA_RELAY_TOTAL_SIZE =
// TODO: measure this.
uint32 constant EVM_RELAY_GAS_COST = 400_000;
// Size of the transaction in bytes.
// TODO: measure this.
uint32 constant EVM_RELAY_TX_SIZE = 1000;
uint32 constant EVM_RELAY_TX_SIZE = 1211;
// Amount of WEI in a microeth
uint256 constant WEI_PER_MICROETH = 1E12;

Expand Down
2 changes: 1 addition & 1 deletion sdk/solana/tbrv3/idl/token_bridge_relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ export type TokenBridgeRelayer = {
{
"name": "deployer",
"docs": [
"Since we are passing on the upgarde authority, the original deployer is the only one",
"Since we are passing on the upgrade authority, the original deployer is the only one",
"who can initialize the program."
],
"writable": true,
Expand Down
66 changes: 44 additions & 22 deletions sdk/solana/tbrv3/token-bridge-relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,34 +354,56 @@ export class SolanaTokenBridgeRelayer {
/**
* Signer: the Program Authority.
*/
async initialize({
owner,
feeRecipient,
admins,
}: {
owner: PublicKey;
feeRecipient: PublicKey;
admins: PublicKey[];
}): Promise<TransactionInstruction> {
async initialize(
signer: PublicKey,
{
owner,
feeRecipient,
admins,
}: {
owner: PublicKey;
feeRecipient: PublicKey;
admins: PublicKey[];
},
evmTransactionGas: bigint,
evmTransactionSize: bigint,
Comment on lines +368 to +369
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both could be just numbers too. 🤔

The real datatype we'd want is a uint... and preferably one with units...

Copy link
Collaborator Author

@scnale scnale Feb 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're both uint64 for some reason. I think that this is excessive for the tx size but I don't recall if this makes sense for the gas limit. I think we chose uint32 in SR, right?

): Promise<TransactionInstruction[]> {

const program = new BpfLoaderUpgradeableProgram(this.programId, this.connection);
const upgradeAuthority = (await program.getdata()).upgradeAuthority;
if (upgradeAuthority === undefined) throwError('The program must be upgradeable');
if (!upgradeAuthority.equals(signer))
throwError(`The signer (${signer}) must be the upgrade authority.
Current authority: ${upgradeAuthority}`);

if (!signer.equals(owner) && !admins.some((key) => signer.equals(key)))
throwError(`The signer must be set as either the owner or an admin`);

const authBadges = admins.map((key) => ({
pubkey: this.account.authBadge(key).address,
isSigner: false,
isWritable: true,
}));

const program = new BpfLoaderUpgradeableProgram(this.programId, this.connection);
const deployer =
(await program.getdata()).upgradeAuthority ?? throwError('The program must be upgradeable');

return await this.program.methods
.initialize(feeRecipient, admins)
.accountsPartial({
deployer,
programData: program.dataAddress,
owner,
})
.remainingAccounts(authBadges)
.instruction();
return Promise.all([
this.program.methods
.initialize(feeRecipient, admins)
.accountsPartial({
deployer: signer,
programData: program.dataAddress,
owner,
})
.remainingAccounts(authBadges)
.instruction(),
this.program.methods
.updateEvmTransactionConfig(bigintToBn(evmTransactionGas), bigintToBn(evmTransactionSize))
.accounts({
signer,
authBadge: this.account.authBadge(signer).address,
tbrConfig: this.account.config().address,
})
.instruction()
]);
}

/* Roles */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use wormhole_anchor_sdk::token_bridge;
#[derive(Accounts)]
#[instruction(admin: Pubkey)]
pub struct Initialize<'info> {
/// Since we are passing on the upgarde authority, the original deployer is the only one
/// Since we are passing on the upgrade authority, the original deployer is the only one
/// who can initialize the program.
#[account(mut)]
pub deployer: Signer<'info>,
Expand Down
63 changes: 36 additions & 27 deletions solana/tests/token-bridge-relayer-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,40 +157,49 @@ describe('Token Bridge Relayer Program', () => {
DEBUG,
);

// Let's credit a badge, to verify that we cannot trigger a denial of service:
await $.airdrop(upgradeAuthorityClient.account.authBadge(adminClient1.publicKey).address);
try {
// Let's credit a badge, to verify that we cannot trigger a denial of service:
await $.airdrop(upgradeAuthorityClient.account.authBadge(adminClient1.publicKey).address);

await upgradeAuthorityClient.initialize({
feeRecipient,
owner: ownerClient.publicKey,
admins: [adminClient1.publicKey, adminClient2.publicKey],
});
await upgradeAuthorityClient.initialize(
{
feeRecipient,
owner: ownerClient.publicKey,
admins: [adminClient1.publicKey, adminClient2.publicKey, upgradeAuthorityClient.publicKey],
},
evmTransactionGas + 1n,
evmTransactionSize + 1n
);

// Verify that the authority has been updated to the new owner.
const { upgradeAuthority } = await bpfProgram.getdata();
expect(upgradeAuthority).deep.equal(ownerClient.publicKey);
// Verify that the authority has been updated to the new owner.
const { upgradeAuthority } = await bpfProgram.getdata();
expect(upgradeAuthority).deep.equal(ownerClient.publicKey);

const config = await unauthorizedClient.read.config();
expect(config.owner).deep.equal(ownerClient.publicKey);
const config = await unauthorizedClient.read.config();
expect(config.owner).deep.equal(ownerClient.publicKey);

// The owner has an auth badge:
expect(await unauthorizedClient.account.authBadge(ownerClient.publicKey).fetch()).deep.equal({
address: ownerClient.publicKey,
});
// The owner has an auth badge:
expect(await unauthorizedClient.account.authBadge(ownerClient.publicKey).fetch()).deep.equal({
address: ownerClient.publicKey,
});

// The admins have an auth badge:
expect(await unauthorizedClient.account.authBadge(adminClient1.publicKey).fetch()).deep.equal({
address: adminClient1.publicKey,
});
expect(await unauthorizedClient.account.authBadge(adminClient2.publicKey).fetch()).deep.equal({
address: adminClient2.publicKey,
});
// The admins have an auth badge:
expect(await unauthorizedClient.account.authBadge(adminClient1.publicKey).fetch()).deep.equal({
address: adminClient1.publicKey,
});
expect(await unauthorizedClient.account.authBadge(adminClient2.publicKey).fetch()).deep.equal({
address: adminClient2.publicKey,
});

// Verify that the accounts reader works:
const adminAccounts = await unauthorizedClient.client.read.allAdminAccounts();
assert.array(adminAccounts).equal([adminClient1.publicKey, adminClient2.publicKey]);
// Verify that the accounts reader works:
const adminAccounts = await unauthorizedClient.client.read.allAdminAccounts();
assert.array(adminAccounts).equal([adminClient1.publicKey, adminClient2.publicKey, upgradeAuthorityClient.publicKey]);
} catch (error) {
throw error;
} finally {
await upgradeAuthorityClient.close();
}

await upgradeAuthorityClient.close();
});

describe('Roles', () => {
Expand Down
14 changes: 7 additions & 7 deletions solana/tests/utils/tbr-wrapper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Connection, PublicKey, Signer, VersionedTransactionResponse } from '@solana/web3.js';
import { Chain } from '@wormhole-foundation/sdk-base';
import { Chain, RoTuple } from '@wormhole-foundation/sdk-base';
import { UniversalAddress } from '@wormhole-foundation/sdk-definitions';
import {
SolanaPriceOracle,
Expand All @@ -13,6 +13,8 @@ import testProgramKeypair from '../../programs/token-bridge-relayer/test-program

const $ = new TestsHelper();

type Tail<T extends RoTuple> = T extends readonly [unknown, ...infer T2] ? T2 : never;

export class TbrWrapper {
readonly client: SolanaTokenBridgeRelayer;
readonly signer: Signer;
Expand Down Expand Up @@ -76,12 +78,10 @@ export class TbrWrapper {
}
}

async initialize(args: {
owner: PublicKey;
feeRecipient: PublicKey;
admins: PublicKey[];
}): Promise<VersionedTransactionResponse | null> {
return $.getTransaction($.sendAndConfirm(await this.client.initialize(args), this.signer));
async initialize(
...args: Tail<Parameters<SolanaTokenBridgeRelayer["initialize"]>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice

): Promise<VersionedTransactionResponse | null> {
return $.getTransaction($.sendAndConfirm(await this.client.initialize(this.signer.publicKey, ...args), this.signer));
}

async submitOwnerTransferRequest(
Expand Down
2 changes: 1 addition & 1 deletion target/idl/token_bridge_relayer.json
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@
{
"name": "deployer",
"docs": [
"Since we are passing on the upgarde authority, the original deployer is the only one",
"Since we are passing on the upgrade authority, the original deployer is the only one",
"who can initialize the program."
],
"writable": true,
Expand Down
2 changes: 1 addition & 1 deletion target/types/token_bridge_relayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ export type TokenBridgeRelayer = {
{
"name": "deployer",
"docs": [
"Since we are passing on the upgarde authority, the original deployer is the only one",
"Since we are passing on the upgrade authority, the original deployer is the only one",
"who can initialize the program."
],
"writable": true,
Expand Down