diff --git a/cli/src/index.ts b/cli/src/index.ts index e848dc1e7..960974fcd 100755 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -675,7 +675,7 @@ yargs(hideBin(process.argv)) await signSendWait(ctx, tx, signer.signer) } for (const transceiver of missingConfig.transceiverPeers) { - const tx = ntt.setWormholeTransceiverPeer(transceiver, signer.address.address) + const tx = ntt.setTransceiverPeer(0, transceiver, signer.address.address) await signSendWait(ctx, tx, signer.signer) } for (const evmChain of missingConfig.evmChains) { @@ -696,10 +696,9 @@ yargs(hideBin(process.argv)) continue; } const solanaNtt = ntt as SolanaNtt; - const tx = solanaNtt.registerTransceiver({ + const tx = solanaNtt.registerWormholeTransceiver({ payer: signer.address.address as AccountAddress, owner: signer.address.address as AccountAddress, - transceiver: solanaNtt.program.programId }) try { await signSendWait(ctx, tx, signer.signer) @@ -1291,7 +1290,7 @@ async function deploySolana( // time by checking it here and failing early (not to mention better // diagnostics). - const emitter = NTT.pdas(providedProgramId).emitterAccount().toBase58(); + const emitter = NTT.transceiverPdas(providedProgramId).emitterAccount().toBase58(); const payerKeypair = Keypair.fromSecretKey(new Uint8Array(JSON.parse(fs.readFileSync(payer).toString()))); // this is not super pretty... I want to initialise the 'ntt' object, but @@ -1787,7 +1786,7 @@ async function getPdas(chain: C, ntt: Ntt; const config = solanaNtt.pdas.configAccount(); - const emitter = solanaNtt.pdas.emitterAccount(); + const emitter = NTT.transceiverPdas(solanaNtt.program.programId).emitterAccount(); const outboxRateLimit = solanaNtt.pdas.outboxRateLimitAccount(); const tokenAuthority = solanaNtt.pdas.tokenAuthority(); const lutAccount = solanaNtt.pdas.lutAccount(); @@ -1826,7 +1825,7 @@ async function nttFromManager( ntt: { manager: nativeManagerAddress, token: null, - transceiver: { wormhole: null }, + transceiver: {}, } }); const diff = await onlyManager.verifyAddresses(); diff --git a/evm/ts/src/ntt.ts b/evm/ts/src/ntt.ts index 09fd4835d..07b4cb8cf 100644 --- a/evm/ts/src/ntt.ts +++ b/evm/ts/src/ntt.ts @@ -15,7 +15,11 @@ import { toUniversal, universalAddress, } from "@wormhole-foundation/sdk-definitions"; -import type { AnyEvmAddress, EvmChains, EvmPlatformType } from "@wormhole-foundation/sdk-evm"; +import type { + AnyEvmAddress, + EvmChains, + EvmPlatformType, +} from "@wormhole-foundation/sdk-evm"; import { EvmAddress, EvmPlatform, @@ -26,6 +30,7 @@ import { import "@wormhole-foundation/sdk-evm-core"; import { + EvmNttTransceiver, Ntt, NttTransceiver, WormholeNttTransceiver, @@ -39,7 +44,10 @@ import { } from "./bindings.js"; export class EvmNttWormholeTranceiver - implements NttTransceiver { + implements + WormholeNttTransceiver, + EvmNttTransceiver +{ transceiver: NttTransceiverBindings.NttTransceiver; constructor( readonly manager: EvmNtt, @@ -52,15 +60,26 @@ export class EvmNttWormholeTranceiver ); } + async getTransceiverType(): Promise { + // NOTE: We hardcode the type here as transceiver type is only available for versions >1.1.0 + // For those versions, we can return `this.transceiver.getTransceiverType()` directly + return "wormhole"; + } + getAddress(): ChainAddress { - return { chain: this.manager.chain, address: toUniversal(this.manager.chain, this.address) }; + return { + chain: this.manager.chain, + address: toUniversal(this.manager.chain, this.address), + }; } encodeFlags(flags: { skipRelay: boolean }): Uint8Array { return new Uint8Array([flags.skipRelay ? 1 : 0]); } - async *setPeer

(peer: ChainAddress

): AsyncGenerator> { + async *setPeer

( + peer: ChainAddress

+ ): AsyncGenerator> { const tx = await this.transceiver.setWormholePeer.populateTransaction( toChainId(peer.chain), universalAddress(peer) @@ -74,8 +93,14 @@ export class EvmNttWormholeTranceiver } async *setPauser(pauser: AccountAddress) { - const canonicalPauser = canonicalAddress({chain: this.manager.chain, address: pauser}); - const tx = await this.transceiver.transferPauserCapability.populateTransaction(canonicalPauser); + const canonicalPauser = canonicalAddress({ + chain: this.manager.chain, + address: pauser, + }); + const tx = + await this.transceiver.transferPauserCapability.populateTransaction( + canonicalPauser + ); yield this.manager.createUnsignedTx(tx, "WormholeTransceiver.setPauser"); } @@ -102,7 +127,10 @@ export class EvmNttWormholeTranceiver toChainId(chain), isEvm ); - yield this.manager.createUnsignedTx(tx, "WormholeTransceiver.setIsEvmChain"); + yield this.manager.createUnsignedTx( + tx, + "WormholeTransceiver.setIsEvmChain" + ); } async *receive(attestation: WormholeNttTransceiver.VAA) { @@ -122,10 +150,11 @@ export class EvmNttWormholeTranceiver } async *setIsWormholeRelayingEnabled(destChain: Chain, enabled: boolean) { - const tx = await this.transceiver.setIsWormholeRelayingEnabled.populateTransaction( - toChainId(destChain), - enabled - ); + const tx = + await this.transceiver.setIsWormholeRelayingEnabled.populateTransaction( + toChainId(destChain), + enabled + ); yield this.manager.createUnsignedTx( tx, "WormholeTransceiver.setWormholeRelayingEnabled" @@ -139,10 +168,11 @@ export class EvmNttWormholeTranceiver } async *setIsSpecialRelayingEnabled(destChain: Chain, enabled: boolean) { - const tx = await this.transceiver.setIsSpecialRelayingEnabled.populateTransaction( - toChainId(destChain), - enabled - ); + const tx = + await this.transceiver.setIsSpecialRelayingEnabled.populateTransaction( + toChainId(destChain), + enabled + ); yield this.manager.createUnsignedTx( tx, "WormholeTransceiver.setSpecialRelayingEnabled" @@ -151,7 +181,8 @@ export class EvmNttWormholeTranceiver } export class EvmNtt - implements Ntt { + implements Ntt +{ tokenAddress: string; readonly chainId: bigint; manager: NttManagerBindings.NttManager; @@ -182,17 +213,32 @@ export class EvmNtt this.provider ); - if (contracts.ntt.transceiver.wormhole != null) { - this.xcvrs = [ - // Enable more Transceivers here - new EvmNttWormholeTranceiver( - this, - contracts.ntt.transceiver.wormhole, - abiBindings! - ), + this.xcvrs = []; + if ( + "wormhole" in contracts.ntt.transceiver && + contracts.ntt.transceiver["wormhole"] + ) { + const transceiverTypes = [ + "wormhole", // wormhole xcvr should be ix 0 + ...Object.keys(contracts.ntt.transceiver).filter((transceiverType) => { + transceiverType !== "wormhole"; + }), ]; - } else { - this.xcvrs = []; + transceiverTypes.map((transceiverType) => { + // we currently only support wormhole transceivers + if (transceiverType !== "wormhole") { + throw new Error(`Unsupported transceiver type: ${transceiverType}`); + } + + // Enable more Transceivers here + this.xcvrs.push( + new EvmNttWormholeTranceiver( + this, + contracts.ntt!.transceiver[transceiverType]!, + abiBindings! + ) + ); + }); } } @@ -211,12 +257,12 @@ export class EvmNtt } async *pause() { - const tx = await this.manager.pause.populateTransaction() + const tx = await this.manager.pause.populateTransaction(); yield this.createUnsignedTx(tx, "Ntt.pause"); } async *unpause() { - const tx = await this.manager.unpause.populateTransaction() + const tx = await this.manager.unpause.populateTransaction(); yield this.createUnsignedTx(tx, "Ntt.unpause"); } @@ -230,13 +276,17 @@ export class EvmNtt async *setOwner(owner: AnyEvmAddress) { const canonicalOwner = new EvmAddress(owner).toString(); - const tx = await this.manager.transferOwnership.populateTransaction(canonicalOwner); + const tx = await this.manager.transferOwnership.populateTransaction( + canonicalOwner + ); yield this.createUnsignedTx(tx, "Ntt.setOwner"); } async *setPauser(pauser: AnyEvmAddress) { const canonicalPauser = new EvmAddress(pauser).toString(); - const tx = await this.manager.transferPauserCapability.populateTransaction(canonicalPauser); + const tx = await this.manager.transferPauserCapability.populateTransaction( + canonicalPauser + ); yield this.createUnsignedTx(tx, "Ntt.setPauser"); } @@ -398,9 +448,14 @@ export class EvmNtt } async *setWormholeTransceiverPeer(peer: ChainAddress) { - // TODO: we only have one right now, so just set the peer on that one - // in the future, these should(?) be keyed by attestation type - yield* this.xcvrs[0]!.setPeer(peer); + yield* this.setTransceiverPeer(0, peer); + } + + async *setTransceiverPeer(ix: number, peer: ChainAddress) { + if (ix >= this.xcvrs.length) { + throw new Error("Transceiver not found"); + } + yield* this.xcvrs[ix]!.setPeer(peer); } async *transfer( @@ -475,7 +530,9 @@ export class EvmNtt } async getOutboundLimit(): Promise { - const encoded: EncodedTrimmedAmount = (await this.manager.getOutboundLimitParams()).limit; + const encoded: EncodedTrimmedAmount = ( + await this.manager.getOutboundLimitParams() + ).limit; const trimmedAmount: TrimmedAmount = decodeTrimmedAmount(encoded); const tokenDecimals = await this.getTokenDecimals(); @@ -492,7 +549,9 @@ export class EvmNtt } async getInboundLimit(fromChain: Chain): Promise { - const encoded: EncodedTrimmedAmount = (await this.manager.getInboundLimitParams(toChainId(fromChain))).limit; + const encoded: EncodedTrimmedAmount = ( + await this.manager.getInboundLimitParams(toChainId(fromChain)) + ).limit; const trimmedAmount: TrimmedAmount = decodeTrimmedAmount(encoded); const tokenDecimals = await this.getTokenDecimals(); @@ -547,7 +606,7 @@ export class EvmNtt manager: this.managerAddress, token: this.tokenAddress, transceiver: { - wormhole: this.xcvrs[0]?.address, + ...(this.xcvrs.length > 0 && { wormhole: this.xcvrs[0]!.address }), }, // TODO: what about the quoter? }; @@ -556,7 +615,7 @@ export class EvmNtt manager: this.managerAddress, token: await this.manager.token(), transceiver: { - wormhole: (await this.manager.getTransceivers())[0]! // TODO: make this more generic + wormhole: (await this.manager.getTransceivers())[0]!, // TODO: make this more generic }, }; @@ -569,7 +628,7 @@ export class EvmNtt delete a[k]; } } - } + }; deleteMatching(remote, local); @@ -612,14 +671,18 @@ function untrim(trimmed: TrimmedAmount, toDecimals: number): bigint { return scale(amount, fromDecimals, toDecimals); } -function scale(amount: bigint, fromDecimals: number, toDecimals: number): bigint { +function scale( + amount: bigint, + fromDecimals: number, + toDecimals: number +): bigint { if (fromDecimals == toDecimals) { return amount; } if (fromDecimals > toDecimals) { - return amount / (10n ** BigInt(fromDecimals - toDecimals)); + return amount / 10n ** BigInt(fromDecimals - toDecimals); } else { - return amount * (10n ** BigInt(toDecimals - fromDecimals)); + return amount * 10n ** BigInt(toDecimals - fromDecimals); } } diff --git a/sdk/__tests__/utils.ts b/sdk/__tests__/utils.ts index 657a131ae..c54b20fc6 100644 --- a/sdk/__tests__/utils.ts +++ b/sdk/__tests__/utils.ts @@ -37,6 +37,7 @@ import solanaTiltKey from "./solana-tilt.json"; // from https://github.com/wormh import { Ntt } from "../definitions/src/index.js"; import "../../evm/ts/src/index.js"; import "../../solana/ts/sdk/index.js"; +import { NTT } from "../../solana/ts/lib/index.js"; import { SolanaNtt } from "../../solana/ts/sdk/index.js"; import { submitAccountantVAA } from "./accountant.js"; @@ -127,7 +128,7 @@ export async function link(chainInfos: Ctx[]) { chain: hubChain, emitter: Wormhole.chainAddress( hubChain, - hub.contracts!.transceiver.wormhole! + hub.contracts!.transceiver["wormhole"]! ).address.toUniversalAddress(), sequence: 0n, }; @@ -524,7 +525,9 @@ async function deploySolana(ctx: Ctx): Promise { token: mint.toBase58(), manager: managerProgramId, transceiver: { - wormhole: managerProgramId, + wormhole: NTT.transceiverPdas(managerProgramId) + .emitterAccount() + .toString(), }, }; @@ -565,10 +568,11 @@ async function deploySolana(ctx: Ctx): Promise { // mindful in the deploy script too. await new Promise((resolve) => setTimeout(resolve, 400)); - const registrTxs = manager.registerTransceiver({ - payer: Wormhole.chainAddress("Solana", keypair.publicKey.toBase58()).address, - owner: Wormhole.chainAddress("Solana", keypair.publicKey.toBase58()).address, - transceiver: manager.program.programId, + const registrTxs = manager.registerWormholeTransceiver({ + payer: Wormhole.chainAddress("Solana", keypair.publicKey.toBase58()) + .address, + owner: Wormhole.chainAddress("Solana", keypair.publicKey.toBase58()) + .address, }); await signSendWait(ctx.context, registrTxs, signer); console.log("Registered transceiver with self"); @@ -578,7 +582,9 @@ async function deploySolana(ctx: Ctx): Promise { ...ctx, contracts: { transceiver: { - wormhole: manager.pdas.emitterAccount().toString(), + wormhole: NTT.transceiverPdas(manager.program.programId) + .emitterAccount() + .toString(), }, manager: manager.program.programId.toString(), token: mint.toString(), @@ -611,7 +617,8 @@ async function setupPeer(targetCtx: Ctx, peerCtx: Ctx) { ); await signSendWait(target, setPeerTxs, signer); - const setXcvrPeerTxs = nttManager.setWormholeTransceiverPeer( + const setXcvrPeerTxs = nttManager.setTransceiverPeer( + 0, // 0 = Wormhole peerTransceiver, sender.address ); @@ -625,7 +632,7 @@ async function setupPeer(targetCtx: Ctx, peerCtx: Ctx) { ) { const nativeSigner = (signer as NativeSigner).unwrap(); const xcvr = WormholeTransceiver__factory.connect( - targetCtx.contracts!.transceiver.wormhole!, + targetCtx.contracts!.transceiver["wormhole"]!, nativeSigner.signer ); const peerChainId = toChainId(peer.chain); diff --git a/sdk/definitions/src/ntt.ts b/sdk/definitions/src/ntt.ts index 96f021e31..485d1cd24 100644 --- a/sdk/definitions/src/ntt.ts +++ b/sdk/definitions/src/ntt.ts @@ -25,6 +25,7 @@ import { transceiverInstructionLayout, transceiverRegistration, } from "./layouts/index.js"; +import { PublicKey } from "@solana/web3.js"; /** * @namespace Ntt @@ -38,7 +39,7 @@ export namespace Ntt { token: string; manager: string; transceiver: { - wormhole?: string; + [type: string]: string; }; quoter?: string; }; @@ -163,21 +164,23 @@ export interface Ntt { isPaused(): Promise; - pause( - payer?: AccountAddress - ): AsyncGenerator>; + pause(payer?: AccountAddress): AsyncGenerator>; - unpause( - payer?: AccountAddress - ): AsyncGenerator>; + unpause(payer?: AccountAddress): AsyncGenerator>; getOwner(): Promise>; getPauser(): Promise | null>; - setOwner(newOwner: AccountAddress, payer?: AccountAddress): AsyncGenerator>; + setOwner( + newOwner: AccountAddress, + payer?: AccountAddress + ): AsyncGenerator>; - setPauser(newOwner: AccountAddress, payer?: AccountAddress): AsyncGenerator>; + setPauser( + newOwner: AccountAddress, + payer?: AccountAddress + ): AsyncGenerator>; getThreshold(): Promise; @@ -188,7 +191,9 @@ export interface Ntt { payer?: AccountAddress ): AsyncGenerator>; - setWormholeTransceiverPeer( + // TODO: replace ix with transceiver type + setTransceiverPeer( + ix: number, peer: ChainAddress, payer?: AccountAddress ): AsyncGenerator>; @@ -226,6 +231,8 @@ export interface Ntt { /** * redeem redeems a set of Attestations to the corresponding transceivers on the destination chain * @param attestations The attestations to redeem, the length should be equal to the number of transceivers + * + * TODO: replace with Map */ redeem( attestations: Ntt.Attestation[], @@ -241,7 +248,13 @@ export interface Ntt { /** Get the peer information for the given chain if it exists */ getPeer(chain: C): Promise | null>; - getTransceiver(ix: number): Promise | null>; + /** Get the transceiver corresponding to index (0 = Wormhole) + * + * TODO: replace ix with transceiver type + */ + getTransceiver( + ix: number + ): Promise | null>; /** * getCurrentOutboundCapacity returns the current outbound capacity of the Ntt manager @@ -256,7 +269,10 @@ export interface Ntt { /** * setOutboundLimit sets the maximum outbound capacity of the Ntt manager */ - setOutboundLimit(limit: bigint, payer?: AccountAddress): AsyncGenerator>; + setOutboundLimit( + limit: bigint, + payer?: AccountAddress + ): AsyncGenerator>; /** * getCurrentInboundCapacity returns the current inbound capacity of the Ntt manager @@ -346,17 +362,27 @@ export interface NttTransceiver< C extends Chain, A extends Ntt.Attestation > { + getTransceiverType(payer?: AccountAddress): Promise; + /** + * Returns transceiver contract address on EVM and `emitterAccount` PDA address on Solana + */ getAddress(): ChainAddress; /** setPeer sets a peer address for a given chain * Note: Admin only */ - setPeer(peer: ChainAddress, payer?: AccountAddress): AsyncGenerator>; + setPeer( + peer: ChainAddress, + payer?: AccountAddress + ): AsyncGenerator>; getPeer(chain: C): Promise | null>; - setPauser(newPauser: AccountAddress, payer?: AccountAddress): AsyncGenerator>; + setPauser( + newPauser: AccountAddress, + payer?: AccountAddress + ): AsyncGenerator>; getPauser(): Promise | null>; @@ -393,6 +419,20 @@ export namespace WormholeNttTransceiver { export interface WormholeNttTransceiver extends NttTransceiver {} +export interface SolanaNttTransceiver< + N extends Network, + C extends Chain, + A extends Ntt.Attestation +> extends NttTransceiver { + programId: PublicKey; +} + +export interface EvmNttTransceiver< + N extends Network, + C extends Chain, + A extends Ntt.Attestation +> extends NttTransceiver {} + declare module "@wormhole-foundation/sdk-definitions" { export namespace WormholeRegistry { interface ProtocolToInterfaceMapping { diff --git a/sdk/route/src/automatic.ts b/sdk/route/src/automatic.ts index e8dd585d4..c7b240c3c 100644 --- a/sdk/route/src/automatic.ts +++ b/sdk/route/src/automatic.ts @@ -318,7 +318,7 @@ export class NttAutomaticRoute token: dstInfo.token, manager: dstInfo.manager, transceiver: { - wormhole: dstInfo.transceiver.wormhole, + wormhole: dstInfo.transceiver["wormhole"]!, }, }, }, diff --git a/sdk/route/src/manual.ts b/sdk/route/src/manual.ts index 0b2f837bf..8eedde3f2 100644 --- a/sdk/route/src/manual.ts +++ b/sdk/route/src/manual.ts @@ -304,7 +304,7 @@ export class NttManualRoute token: dstInfo.token, manager: dstInfo.manager, transceiver: { - wormhole: dstInfo.transceiver.wormhole, + wormhole: dstInfo.transceiver["wormhole"]!, }, }, }, diff --git a/solana/Anchor.toml b/solana/Anchor.toml index 7554a6de7..269b1b7b7 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -9,6 +9,7 @@ skip-lint = false [programs.localnet] dummy_transfer_hook = "BgabMDLaxsyB7eGMBt9L22MSk9KMrL4zY2iNe14kyFP5" example_native_token_transfers = "nttiK1SepaQt6sZ4WGW5whvc9tEnGXGxuKeptcQPCcS" +ntt_transceiver = "Ee6jpX9oq2EsGuqGb6iZZxvtcpmMGZk8SAUbnQy4jcHR" ntt_quoter = "9jFBLvMZZERVmeY4tbq5MejbXRE18paGEuoB6xVJZgGe" wormhole_governance = "wgvEiKVzX9yyEoh41jZAdC6JqGUTS4CFXbFGBV5TKdZ" diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 4424e6667..777509a75 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -1394,7 +1394,7 @@ checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] name = "dummy-transfer-hook" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anchor-lang", "anchor-spl", @@ -1553,7 +1553,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "example-native-token-transfers" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anchor-lang", "anchor-spl", @@ -2476,7 +2476,7 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "ntt-messages" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anchor-lang", "hex", @@ -2486,7 +2486,7 @@ dependencies = [ [[package]] name = "ntt-quoter" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anchor-lang", "cfg-if", @@ -2496,6 +2496,21 @@ dependencies = [ "wormhole-solana-utils", ] +[[package]] +name = "ntt-transceiver" +version = "3.0.0" +dependencies = [ + "anchor-lang", + "anchor-spl", + "example-native-token-transfers", + "hex", + "ntt-messages", + "solana-program", + "wormhole-anchor-sdk", + "wormhole-io", + "wormhole-sdk", +] + [[package]] name = "num" version = "0.2.1" @@ -6392,7 +6407,7 @@ dependencies = [ [[package]] name = "wormhole-governance" -version = "2.0.0" +version = "3.0.0" dependencies = [ "anchor-lang", "hex", diff --git a/solana/Makefile b/solana/Makefile index af6ae7154..5ad3a801a 100644 --- a/solana/Makefile +++ b/solana/Makefile @@ -22,8 +22,10 @@ cargo-build: # because the javascript library does not support generics yet, and just panics anchor-build: anchor build --arch sbf - @echo "Removing generics from target/idl/example_native_token_transfers.json" - ./scripts/patch-idl target/idl/example_native_token_transfers.json + for jsonfile in target/idl/*.json; do \ + echo "Removing generics from" $$jsonfile; \ + ./scripts/patch-idl $$jsonfile; \ + done prod-build: anchor build --verifiable diff --git a/solana/modules/ntt-messages/Cargo.toml b/solana/modules/ntt-messages/Cargo.toml index b3443dd67..6ca1345bd 100644 --- a/solana/modules/ntt-messages/Cargo.toml +++ b/solana/modules/ntt-messages/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ntt-messages" -version = "2.0.0" +version = "3.0.0" edition = "2021" [features] diff --git a/solana/modules/ntt-messages/src/transceiver.rs b/solana/modules/ntt-messages/src/transceiver.rs index 1bca121d4..798fc1b65 100644 --- a/solana/modules/ntt-messages/src/transceiver.rs +++ b/solana/modules/ntt-messages/src/transceiver.rs @@ -23,6 +23,43 @@ pub struct TransceiverMessageData { pub ntt_manager_payload: NttManagerMessage, } +/// This struct is for zero-copy deserialization of +/// `ValidatedTransceiverMessage::message()` in the redeem ix +pub struct TransceiverMessageDataBytes<'a, A: MaybeSpace> { + _phantom: PhantomData, + span: &'a [u8], +} + +impl AsRef<[u8]> for TransceiverMessageDataBytes<'_, A> { + fn as_ref(&self) -> &[u8] { + self.span + } +} + +impl<'a, A: MaybeSpace> TransceiverMessageDataBytes<'a, A> { + pub fn source_ntt_manager(&self) -> [u8; 32] { + self.span[..32].try_into().unwrap() + } + + pub fn recipient_ntt_manager(&self) -> [u8; 32] { + self.span[32..64].try_into().unwrap() + } + + pub fn ntt_manager_payload(&self) -> NttManagerMessage + where + A: AnchorDeserialize, + { + NttManagerMessage::deserialize(&mut &self.span[64..]).unwrap() + } + + pub fn parse(span: &'a [u8]) -> TransceiverMessageDataBytes<'a, A> { + TransceiverMessageDataBytes { + _phantom: PhantomData, + span, + } + } +} + #[derive(Eq, PartialEq, Clone, Debug)] pub struct TransceiverMessage { _phantom: PhantomData, diff --git a/solana/programs/dummy-transfer-hook/Cargo.toml b/solana/programs/dummy-transfer-hook/Cargo.toml index 9e408629d..a7b50b7b8 100644 --- a/solana/programs/dummy-transfer-hook/Cargo.toml +++ b/solana/programs/dummy-transfer-hook/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dummy-transfer-hook" -version = "2.0.0" +version = "3.0.0" description = "Created with Anchor" edition = "2021" diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index c248cb6c0..f98cd993e 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "example-native-token-transfers" -version = "2.0.0" +version = "3.0.0" description = "Example implementation of native token transfer standard" edition = "2021" diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index e7ffadbe5..ee07ed5f1 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -5,6 +5,23 @@ use ntt_messages::{chain_id::ChainId, mode::Mode}; use crate::bitmap::Bitmap; +/// This is a hack to re-export some modules that anchor generates as +/// pub(crate), as it's not possible to directly re-export a module with a +/// relaxed visibility. +/// Instead, we define public modules with the *same* name, and pub use all the +/// members of the original. +/// Within this crate, this module should not be used. Outside of this crate, +/// importing `anchor_reexports::*` achieves what we want. +pub mod anchor_reexports { + pub mod __cpi_client_accounts_not_paused_config { + pub use super::super::__cpi_client_accounts_not_paused_config::*; + } + + pub mod __client_accounts_not_paused_config { + pub use super::super::__client_accounts_not_paused_config::*; + } +} + #[account] #[derive(InitSpace)] pub struct Config { @@ -49,7 +66,7 @@ pub struct NotPausedConfig<'info> { #[account( constraint = !config.paused @ crate::error::NTTError::Paused, )] - config: Account<'info, Config>, + pub config: Account<'info, Config>, } impl<'info> Deref for NotPausedConfig<'info> { diff --git a/solana/programs/example-native-token-transfers/src/instructions/mark_outbox_item_as_released.rs b/solana/programs/example-native-token-transfers/src/instructions/mark_outbox_item_as_released.rs new file mode 100644 index 000000000..d460049f6 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/mark_outbox_item_as_released.rs @@ -0,0 +1,36 @@ +use crate::{ + config::*, error::NTTError, queue::outbox::OutboxItem, + registered_transceiver::RegisteredTransceiver, +}; +use anchor_lang::prelude::*; + +pub const OUTBOX_ITEM_SIGNER_SEED: &[u8] = b"outbox_item_signer"; + +#[derive(Accounts)] +pub struct MarkOutboxItemAsReleased<'info> { + #[account( + seeds = [OUTBOX_ITEM_SIGNER_SEED], + seeds::program = transceiver.transceiver_address, + bump + )] + pub signer: Signer<'info>, + + pub config: NotPausedConfig<'info>, + + #[account( + mut, + constraint = !outbox_item.released.get(transceiver.id)? @ NTTError::MessageAlreadySent, + )] + pub outbox_item: Account<'info, OutboxItem>, + + #[account( + constraint = config.enabled_transceivers.get(transceiver.id)? @ NTTError::DisabledTransceiver + )] + pub transceiver: Account<'info, RegisteredTransceiver>, +} + +pub fn mark_outbox_item_as_released(ctx: Context) -> Result { + let accs = ctx.accounts; + let released = accs.outbox_item.try_release(accs.transceiver.id)?; + Ok(released) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/instructions/mod.rs index ed009b00c..d9fec7be5 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/mod.rs @@ -1,6 +1,7 @@ pub mod admin; pub mod initialize; pub mod luts; +pub mod mark_outbox_item_as_released; pub mod redeem; pub mod release_inbound; pub mod transfer; @@ -8,6 +9,7 @@ pub mod transfer; pub use admin::*; pub use initialize::*; pub use luts::*; +pub use mark_outbox_item_as_released::*; pub use redeem::*; pub use release_inbound::*; pub use transfer::*; diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index d26c6c9c0..ab594e292 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -24,28 +24,29 @@ pub struct Redeem<'info> { // NOTE: this works when the contract is paused #[account( - constraint = config.threshold > 0 @ NTTError::ZeroThreshold, + constraint = config.threshold > 0 @ NTTError::ZeroThreshold )] pub config: Account<'info, Config>, #[account( - seeds = [NttManagerPeer::SEED_PREFIX, transceiver_message.from_chain.id.to_be_bytes().as_ref()], - constraint = peer.address == transceiver_message.message.source_ntt_manager @ NTTError::InvalidNttManagerPeer, + seeds = [NttManagerPeer::SEED_PREFIX, ValidatedTransceiverMessage::>::from_chain(&transceiver_message)?.id.to_be_bytes().as_ref()], + constraint = peer.address == ValidatedTransceiverMessage::>::message(&transceiver_message.try_borrow_data()?[..])?.source_ntt_manager() @ NTTError::InvalidNttManagerPeer, bump = peer.bump, )] pub peer: Account<'info, NttManagerPeer>, #[account( // check that the message is targeted to this chain - constraint = transceiver_message.message.ntt_manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + constraint = ValidatedTransceiverMessage::>::message(&transceiver_message.try_borrow_data()?[..])?.ntt_manager_payload().payload.to_chain == config.chain_id @ NTTError::InvalidChainId, // check that we're the intended recipient - constraint = transceiver_message.message.recipient_ntt_manager == crate::ID.to_bytes() @ NTTError::InvalidRecipientNttManager, + constraint = ValidatedTransceiverMessage::>::message(&transceiver_message.try_borrow_data()?[..])?.recipient_ntt_manager() == crate::ID.to_bytes() @ NTTError::InvalidRecipientNttManager, // NOTE: we don't replay protect VAAs. Instead, we replay protect // executing the messages themselves with the [`released`] flag. - owner = transceiver.transceiver_address, + owner = transceiver.transceiver_address )] - pub transceiver_message: - Account<'info, ValidatedTransceiverMessage>>, + /// CHECK: `transceiver_message` has to be manually deserialized as Anchor + /// `Account` and `owner` constraints are mutually-exclusive + pub transceiver_message: UncheckedAccount<'info>, #[account( constraint = config.enabled_transceivers.get(transceiver.id)? @ NTTError::DisabledTransceiver @@ -63,8 +64,8 @@ pub struct Redeem<'info> { space = 8 + InboxItem::INIT_SPACE, seeds = [ InboxItem::SEED_PREFIX, - transceiver_message.message.ntt_manager_payload.keccak256( - transceiver_message.from_chain + ValidatedTransceiverMessage::>::message(&transceiver_message.try_borrow_data()?[..])?.ntt_manager_payload().keccak256( + ValidatedTransceiverMessage::>::from_chain(&transceiver_message)? ).as_ref(), ], bump, @@ -87,7 +88,7 @@ pub struct Redeem<'info> { mut, seeds = [ InboxRateLimit::SEED_PREFIX, - transceiver_message.from_chain.id.to_be_bytes().as_ref(), + ValidatedTransceiverMessage::>::from_chain(&transceiver_message)?.id.to_be_bytes().as_ref(), ], bump, )] @@ -105,8 +106,13 @@ pub struct RedeemArgs {} pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let accs = ctx.accounts; + let transceiver_message: ValidatedTransceiverMessage> = + ValidatedTransceiverMessage::try_from( + &accs.transceiver_message, + &accs.transceiver.transceiver_address, + )?; let message: NttManagerMessage> = - accs.transceiver_message.message.ntt_manager_payload.clone(); + transceiver_message.message.ntt_manager_payload.clone(); // Calculate the scaled amount based on the appropriate decimal encoding for the token. // Return an error if the resulting amount overflows. diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 3f10f3c98..1cf9cdf4b 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -63,7 +63,7 @@ pub const TOKEN_AUTHORITY_SEED: &[u8] = b"token_authority"; /// user, atomically). pub const SESSION_AUTHORITY_SEED: &[u8] = b"session_authority"; -pub const VERSION: &str = "2.0.0"; +pub const VERSION: &str = "3.0.0"; #[program] pub mod example_native_token_transfers { @@ -152,6 +152,10 @@ pub mod example_native_token_transfers { instructions::set_inbound_limit(ctx, args) } + pub fn mark_outbox_item_as_released(ctx: Context) -> Result { + instructions::mark_outbox_item_as_released(ctx) + } + // standalone transceiver stuff pub fn set_wormhole_peer( @@ -184,5 +188,18 @@ pub mod example_native_token_transfers { } } +// The Version struct is just a dummy type because anchor needs every function +// to have a context. When compiled in CPI mode, anchor generates code that +// assumes that the struct has a lifetime parameter. So in that mode, we bind a +// dummy lifetime parameter (and use it in a dummy account). +// When compiling normally, we don't do this, and just use an empty struct, which anchor is happy with. +#[cfg(feature = "cpi")] +#[derive(Accounts)] +pub struct Version<'info> { + /// CHECK: refer to comment above + pub dummy: UncheckedAccount<'info>, +} + +#[cfg(not(feature = "cpi"))] #[derive(Accounts)] pub struct Version {} diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index d33b598e6..f58ebc10a 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -1,5 +1,8 @@ -use anchor_lang::prelude::*; -use ntt_messages::{chain_id::ChainId, transceiver::TransceiverMessageData}; +use anchor_lang::{prelude::*, system_program, Discriminator}; +use ntt_messages::{ + chain_id::ChainId, + transceiver::{TransceiverMessageData, TransceiverMessageDataBytes}, +}; use std::{collections::HashMap, marker::PhantomData}; #[account] @@ -11,6 +14,44 @@ pub struct ValidatedTransceiverMessage ValidatedTransceiverMessage { pub const SEED_PREFIX: &'static [u8] = b"transceiver_message"; + + pub fn discriminator_check(data: &[u8]) -> Result<()> { + if data.len() < Self::DISCRIMINATOR.len() { + return Err(ErrorCode::AccountDiscriminatorNotFound.into()); + } + let given_disc = &data[..8]; + if Self::DISCRIMINATOR != given_disc { + return Err(ErrorCode::AccountDiscriminatorMismatch.into()); + } + Ok(()) + } + + pub fn try_from(info: &UncheckedAccount, expected_owner: &Pubkey) -> Result { + if info.owner == &system_program::ID && info.lamports() == 0 { + return Err(ErrorCode::AccountNotInitialized.into()); + } + if *info.owner != *expected_owner { + return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram) + .with_pubkeys((*info.owner, *expected_owner))); + } + let mut data: &[u8] = &info.try_borrow_data()?; + ValidatedTransceiverMessage::try_deserialize(&mut data) + } + + pub fn from_chain(info: &UncheckedAccount) -> Result { + let data: &[u8] = &info.try_borrow_data().unwrap(); + Self::discriminator_check(data)?; + Ok(ChainId { + // This is LE bytes because we deserialize using Borsh. + // Not to be confused with the wire format (which is BE bytes) + id: u16::from_le_bytes(data[8..10].try_into().unwrap()), + }) + } + + pub fn message(data: &[u8]) -> Result> { + Self::discriminator_check(data)?; + Ok(TransceiverMessageDataBytes::parse(&data[10..])) + } } // This is a hack to get around the fact that the IDL generator doesn't support diff --git a/solana/programs/ntt-quoter/Cargo.toml b/solana/programs/ntt-quoter/Cargo.toml index ee06ec7ae..e804d68be 100644 --- a/solana/programs/ntt-quoter/Cargo.toml +++ b/solana/programs/ntt-quoter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ntt-quoter" -version = "2.0.0" +version = "3.0.0" edition = "2021" [lib] diff --git a/solana/programs/ntt-transceiver/Cargo.toml b/solana/programs/ntt-transceiver/Cargo.toml new file mode 100644 index 000000000..d9be52d5c --- /dev/null +++ b/solana/programs/ntt-transceiver/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "ntt-transceiver" +version = "3.0.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "ntt_transceiver" + +[features] +no-entrypoint = [] +no-idl = [] +idl-build = [ + "anchor-lang/idl-build", + "anchor-spl/idl-build", + "example-native-token-transfers/idl-build" +] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +mainnet = [ "wormhole-anchor-sdk/mainnet" ] +solana-devnet = [ "wormhole-anchor-sdk/solana-devnet" ] +tilt-devnet = [ "wormhole-anchor-sdk/tilt-devnet" ] +tilt-devnet2 = [ "tilt-devnet" ] + +[lints] +workspace = true + +[dependencies] +ntt-messages = { path = "../../modules/ntt-messages", features = ["anchor", "hash"] } +anchor-lang.workspace = true +anchor-spl.workspace = true +solana-program.workspace = true + +wormhole-anchor-sdk.workspace = true +wormhole-io.workspace = true +wormhole-sdk.workspace = true + +example-native-token-transfers = { path = "../example-native-token-transfers", features = ["no-entrypoint", "cpi"] } + +[dev-dependencies] +hex.workspace = true diff --git a/solana/programs/ntt-transceiver/Xargo.toml b/solana/programs/ntt-transceiver/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/solana/programs/ntt-transceiver/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/solana/programs/ntt-transceiver/src/lib.rs b/solana/programs/ntt-transceiver/src/lib.rs new file mode 100644 index 000000000..6f3e45dc1 --- /dev/null +++ b/solana/programs/ntt-transceiver/src/lib.rs @@ -0,0 +1,52 @@ +use anchor_lang::prelude::*; +pub mod messages; +pub mod peer; +pub mod wormhole; + +use wormhole::instructions::*; + +declare_id!("Ee6jpX9oq2EsGuqGb6iZZxvtcpmMGZk8SAUbnQy4jcHR"); + +pub const TRANSCEIVER_TYPE: &str = "wormhole"; + +#[program] +pub mod ntt_transceiver { + + use super::*; + + pub fn transceiver_type(_ctx: Context) -> Result { + Ok(TRANSCEIVER_TYPE.to_string()) + } + + pub fn set_wormhole_peer( + ctx: Context, + args: SetTransceiverPeerArgs, + ) -> Result<()> { + set_transceiver_peer(ctx, args) + } + + pub fn receive_wormhole_message(ctx: Context) -> Result<()> { + wormhole::instructions::receive_message(ctx) + } + + pub fn release_wormhole_outbound( + ctx: Context, + args: ReleaseOutboundArgs, + ) -> Result<()> { + wormhole::instructions::release_outbound(ctx, args) + } + + pub fn broadcast_wormhole_id(ctx: Context) -> Result<()> { + wormhole::instructions::broadcast_id(ctx) + } + + pub fn broadcast_wormhole_peer( + ctx: Context, + args: BroadcastPeerArgs, + ) -> Result<()> { + wormhole::instructions::broadcast_peer(ctx, args) + } +} + +#[derive(Accounts)] +pub struct TransceiverType {} diff --git a/solana/programs/ntt-transceiver/src/messages.rs b/solana/programs/ntt-transceiver/src/messages.rs new file mode 100644 index 000000000..d33b598e6 --- /dev/null +++ b/solana/programs/ntt-transceiver/src/messages.rs @@ -0,0 +1,47 @@ +use anchor_lang::prelude::*; +use ntt_messages::{chain_id::ChainId, transceiver::TransceiverMessageData}; +use std::{collections::HashMap, marker::PhantomData}; + +#[account] +#[derive(InitSpace)] +pub struct ValidatedTransceiverMessage { + pub from_chain: ChainId, + pub message: TransceiverMessageData, +} + +impl ValidatedTransceiverMessage { + pub const SEED_PREFIX: &'static [u8] = b"transceiver_message"; +} + +// This is a hack to get around the fact that the IDL generator doesn't support +// PhantomData. The generator uses the following functions, so we just mix them onto PhantomData. +// +// These types are technically more general than the actual ones, but we can't +// import the actual types from anchor-syn because that crate has a bug where it +// doesn't build against the solana bpf target (due to a missing function). +// Luckily, we don't need to reference those types, as we just want to omit PhantomData from the IDL anyway. +pub trait Hack { + fn __anchor_private_full_path() -> String; + fn __anchor_private_insert_idl_defined(_a: &mut HashMap); + fn __anchor_private_gen_idl_type() -> Option; +} + +impl Hack for PhantomData { + fn __anchor_private_full_path() -> String { + String::new() + } + fn __anchor_private_insert_idl_defined(_a: &mut HashMap) {} + fn __anchor_private_gen_idl_type() -> Option { + None + } +} + +impl Hack for ProgramData { + fn __anchor_private_full_path() -> String { + String::new() + } + fn __anchor_private_insert_idl_defined(_a: &mut HashMap) {} + fn __anchor_private_gen_idl_type() -> Option { + None + } +} diff --git a/solana/programs/ntt-transceiver/src/peer.rs b/solana/programs/ntt-transceiver/src/peer.rs new file mode 100644 index 000000000..4080c439d --- /dev/null +++ b/solana/programs/ntt-transceiver/src/peer.rs @@ -0,0 +1,13 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +/// A peer on another chain. Stored in a PDA seeded by the chain id. +pub struct TransceiverPeer { + pub bump: u8, + pub address: [u8; 32], +} + +impl TransceiverPeer { + pub const SEED_PREFIX: &'static [u8] = b"transceiver_peer"; +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/accounts.rs b/solana/programs/ntt-transceiver/src/wormhole/accounts.rs new file mode 100644 index 000000000..2646c8a57 --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/accounts.rs @@ -0,0 +1,88 @@ +use anchor_lang::prelude::*; +use wormhole_anchor_sdk::wormhole; +use wormhole_io::TypePrefixedPayload; + +// TODO: should we add emitter in here too? +#[derive(Accounts)] +pub struct WormholeAccounts<'info> { + // wormhole stuff + #[account(mut)] + /// CHECK: address will be checked by the wormhole core bridge + pub bridge: Account<'info, wormhole::BridgeData>, + + #[account(mut)] + /// CHECK: account will be checked by the wormhole core bridge + pub fee_collector: UncheckedAccount<'info>, + + #[account(mut)] + /// CHECK: account will be checked and maybe initialized by the wormhole core bridge + pub sequence: UncheckedAccount<'info>, + + pub program: Program<'info, wormhole::program::Wormhole>, + + pub system_program: Program<'info, System>, + + // legacy + pub clock: Sysvar<'info, Clock>, + pub rent: Sysvar<'info, Rent>, +} + +pub fn post_message<'info, A: TypePrefixedPayload>( + wormhole: &WormholeAccounts<'info>, + payer: AccountInfo<'info>, + message: AccountInfo<'info>, + emitter: AccountInfo<'info>, + emitter_bump: u8, + payload: &A, + additional_seeds: &[&[&[u8]]], +) -> Result<()> { + let batch_id = 0; + + pay_wormhole_fee(wormhole, &payer)?; + + let ix = wormhole::PostMessage { + config: wormhole.bridge.to_account_info(), + message, + emitter, + sequence: wormhole.sequence.to_account_info(), + payer: payer.to_account_info(), + fee_collector: wormhole.fee_collector.to_account_info(), + clock: wormhole.clock.to_account_info(), + rent: wormhole.rent.to_account_info(), + system_program: wormhole.system_program.to_account_info(), + }; + + let seeds: &[&[&[&[u8]]]] = &[ + &[&[b"emitter".as_slice(), &[emitter_bump]]], + additional_seeds, + ]; + + wormhole::post_message( + CpiContext::new_with_signer(wormhole.program.to_account_info(), ix, &seeds.concat()), + batch_id, + TypePrefixedPayload::to_vec_payload(payload), + wormhole::Finality::Finalized, + )?; + + Ok(()) +} + +fn pay_wormhole_fee<'info>( + wormhole: &WormholeAccounts<'info>, + payer: &AccountInfo<'info>, +) -> Result<()> { + if wormhole.bridge.fee() > 0 { + anchor_lang::system_program::transfer( + CpiContext::new( + wormhole.system_program.to_account_info(), + anchor_lang::system_program::Transfer { + from: payer.to_account_info(), + to: wormhole.fee_collector.to_account_info(), + }, + ), + wormhole.bridge.fee(), + )?; + } + + Ok(()) +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/instructions/admin.rs b/solana/programs/ntt-transceiver/src/wormhole/instructions/admin.rs new file mode 100644 index 000000000..b606212ff --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/instructions/admin.rs @@ -0,0 +1,47 @@ +use crate::peer::TransceiverPeer; +use anchor_lang::prelude::*; +use example_native_token_transfers::config::Config; +use ntt_messages::chain_id::ChainId; + +#[derive(Accounts)] +#[instruction(args: SetTransceiverPeerArgs)] +pub struct SetTransceiverPeer<'info> { + #[account( + has_one = owner, + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + init, + space = 8 + TransceiverPeer::INIT_SPACE, + payer = payer, + seeds = [TransceiverPeer::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], + bump + )] + pub peer: Account<'info, TransceiverPeer>, + + pub system_program: Program<'info, System>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct SetTransceiverPeerArgs { + pub chain_id: ChainId, + pub address: [u8; 32], +} + +pub fn set_transceiver_peer( + ctx: Context, + args: SetTransceiverPeerArgs, +) -> Result<()> { + ctx.accounts.peer.set_inner(TransceiverPeer { + bump: ctx.bumps.peer, + address: args.address, + }); + + Ok(()) +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/instructions/broadcast_id.rs b/solana/programs/ntt-transceiver/src/wormhole/instructions/broadcast_id.rs new file mode 100644 index 000000000..cbc67a10e --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/instructions/broadcast_id.rs @@ -0,0 +1,54 @@ +use crate::wormhole::accounts::*; +use anchor_lang::prelude::*; +use anchor_spl::token_interface; +use example_native_token_transfers::config::*; +use ntt_messages::transceivers::wormhole::WormholeTransceiverInfo; + +#[derive(Accounts)] +pub struct BroadcastId<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: Account<'info, Config>, + + #[account( + address = config.mint, + )] + pub mint: InterfaceAccount<'info, token_interface::Mint>, + + /// CHECK: initialized and written to by wormhole core bridge + #[account(mut)] + pub wormhole_message: Signer<'info>, + + #[account( + seeds = [b"emitter"], + bump + )] + /// CHECK: The seeds constraint ensures that this is the correct address + pub emitter: UncheckedAccount<'info>, + + pub wormhole: WormholeAccounts<'info>, +} + +pub fn broadcast_id(ctx: Context) -> Result<()> { + let accs = ctx.accounts; + let message = WormholeTransceiverInfo { + manager_address: accs.config.to_account_info().owner.to_bytes(), + manager_mode: accs.config.mode, + token_address: accs.mint.to_account_info().key.to_bytes(), + token_decimals: accs.mint.decimals, + }; + + // TODO: should we send this as an unreliable message into a PDA? + post_message( + &accs.wormhole, + accs.payer.to_account_info(), + accs.wormhole_message.to_account_info(), + accs.emitter.to_account_info(), + ctx.bumps.emitter, + &message, + &[], + )?; + + Ok(()) +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/instructions/broadcast_peer.rs b/solana/programs/ntt-transceiver/src/wormhole/instructions/broadcast_peer.rs new file mode 100644 index 000000000..96227d80f --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/instructions/broadcast_peer.rs @@ -0,0 +1,59 @@ +use crate::{peer::TransceiverPeer, wormhole::accounts::*}; +use anchor_lang::prelude::*; +use example_native_token_transfers::config::*; +use ntt_messages::{chain_id::ChainId, transceivers::wormhole::WormholeTransceiverRegistration}; + +#[derive(Accounts)] +#[instruction(args: BroadcastPeerArgs)] +pub struct BroadcastPeer<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: Account<'info, Config>, + + #[account( + seeds = [TransceiverPeer::SEED_PREFIX, args.chain_id.to_be_bytes().as_ref()], + bump + )] + pub peer: Account<'info, TransceiverPeer>, + + /// CHECK: initialized and written to by wormhole core bridge + #[account(mut)] + pub wormhole_message: Signer<'info>, + + #[account( + seeds = [b"emitter"], + bump + )] + /// CHECK: The seeds constraint ensures that this is the correct address + pub emitter: UncheckedAccount<'info>, + + pub wormhole: WormholeAccounts<'info>, +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct BroadcastPeerArgs { + pub chain_id: u16, +} + +pub fn broadcast_peer(ctx: Context, args: BroadcastPeerArgs) -> Result<()> { + let accs = ctx.accounts; + + let message = WormholeTransceiverRegistration { + chain_id: ChainId { id: args.chain_id }, + transceiver_address: accs.peer.address, + }; + + // TODO: should we send this as an unreliable message into a PDA? + post_message( + &accs.wormhole, + accs.payer.to_account_info(), + accs.wormhole_message.to_account_info(), + accs.emitter.to_account_info(), + ctx.bumps.emitter, + &message, + &[], + )?; + + Ok(()) +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/instructions/mod.rs b/solana/programs/ntt-transceiver/src/wormhole/instructions/mod.rs new file mode 100644 index 000000000..482396b70 --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/instructions/mod.rs @@ -0,0 +1,11 @@ +pub mod admin; +pub mod broadcast_id; +pub mod broadcast_peer; +pub mod receive_message; +pub mod release_outbound; + +pub use admin::*; +pub use broadcast_id::*; +pub use broadcast_peer::*; +pub use receive_message::*; +pub use release_outbound::*; diff --git a/solana/programs/ntt-transceiver/src/wormhole/instructions/receive_message.rs b/solana/programs/ntt-transceiver/src/wormhole/instructions/receive_message.rs new file mode 100644 index 000000000..4b70d25ae --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/instructions/receive_message.rs @@ -0,0 +1,76 @@ +use crate::{messages::ValidatedTransceiverMessage, peer::TransceiverPeer}; +use anchor_lang::prelude::*; +use example_native_token_transfers::{ + config::{anchor_reexports::*, *}, + error::NTTError, + transfer::Payload, +}; +use ntt_messages::{ + chain_id::ChainId, + ntt::NativeTokenTransfer, + transceiver::{TransceiverMessage, TransceiverMessageData}, + transceivers::wormhole::WormholeTransceiver, +}; +use wormhole_anchor_sdk::wormhole::PostedVaa; + +#[derive(Accounts)] +pub struct ReceiveMessage<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: NotPausedConfig<'info>, + + #[account( + seeds = [TransceiverPeer::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], + constraint = peer.address == *vaa.emitter_address() @ NTTError::InvalidTransceiverPeer, + bump = peer.bump, + )] + pub peer: Account<'info, TransceiverPeer>, + + // TODO: Consider using VaaAccount from wormhole-solana-vaa crate. Using a zero-copy reader + // will allow this instruction to be generic (instead of strictly specifying NativeTokenTransfer + // as the message type). + #[account( + // check that the messages is targeted to this chain + constraint = vaa.message().ntt_manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + // NOTE: we don't replay protect VAAs. Instead, we replay protect + // executing the messages themselves with the [`released`] flag. + )] + pub vaa: Account< + 'info, + PostedVaa>>, + >, + + #[account( + init, + payer = payer, + space = 8 + ValidatedTransceiverMessage::>>::INIT_SPACE, + seeds = [ + ValidatedTransceiverMessage::>>::SEED_PREFIX, + vaa.emitter_chain().to_be_bytes().as_ref(), + vaa.message().ntt_manager_payload.id.as_ref(), + ], + bump, + )] + // NOTE: in order to handle multiple transceivers, we can just augment the + // inbox item transfer struct with a bitmap storing which transceivers have + // attested to the transfer. Then we only release it if there's quorum. + // We would need to maybe_init this account in that case. + pub transceiver_message: + Account<'info, ValidatedTransceiverMessage>>, + + pub system_program: Program<'info, System>, +} + +pub fn receive_message(ctx: Context) -> Result<()> { + let message = ctx.accounts.vaa.message().message_data.clone(); + let chain_id = ctx.accounts.vaa.emitter_chain(); + ctx.accounts + .transceiver_message + .set_inner(ValidatedTransceiverMessage { + from_chain: ChainId { id: chain_id }, + message, + }); + + Ok(()) +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/instructions/release_outbound.rs b/solana/programs/ntt-transceiver/src/wormhole/instructions/release_outbound.rs new file mode 100644 index 000000000..eecb0ff1c --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/instructions/release_outbound.rs @@ -0,0 +1,141 @@ +use crate::wormhole::accounts::*; +use anchor_lang::prelude::*; +use example_native_token_transfers::{ + config::{anchor_reexports::*, *}, + error::NTTError, + instructions::OUTBOX_ITEM_SIGNER_SEED, + program::ExampleNativeTokenTransfers, + queue::outbox::OutboxItem, + registered_transceiver::RegisteredTransceiver, + transfer::Payload, +}; +use ntt_messages::{ + ntt::NativeTokenTransfer, ntt_manager::NttManagerMessage, transceiver::TransceiverMessage, + transceivers::wormhole::WormholeTransceiver, +}; + +#[derive(Accounts)] +pub struct ReleaseOutbound<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: NotPausedConfig<'info>, + + #[account( + mut, + constraint = !outbox_item.released.get(transceiver.id)? @ NTTError::MessageAlreadySent, + )] + pub outbox_item: Account<'info, OutboxItem>, + + #[account( + constraint = transceiver.transceiver_address == crate::ID, + constraint = config.enabled_transceivers.get(transceiver.id)? @ NTTError::DisabledTransceiver + )] + pub transceiver: Account<'info, RegisteredTransceiver>, + + #[account( + mut, + seeds = [b"message", outbox_item.key().as_ref()], + bump, + )] + /// CHECK: initialized and written to by wormhole core bridge + pub wormhole_message: UncheckedAccount<'info>, + + #[account( + seeds = [b"emitter"], + bump + )] + // TODO: do we want to put anything in here? + /// CHECK: wormhole uses this as the emitter address + pub emitter: UncheckedAccount<'info>, + + pub wormhole: WormholeAccounts<'info>, + + // NOTE: we put `manager` and `outbox_item_signer` at the end so that the generated + // IDL does not clash with the baked-in transceiver IDL in the manager + pub manager: Program<'info, ExampleNativeTokenTransfers>, + + #[account( + seeds = [OUTBOX_ITEM_SIGNER_SEED], + bump + )] + /// CHECK: this PDA is used to sign the CPI into NTT manager program + pub outbox_item_signer: UncheckedAccount<'info>, +} + +impl<'info> ReleaseOutbound<'info> { + pub fn mark_outbox_item_as_released(&self, bump_seed: u8) -> Result { + let result = example_native_token_transfers::cpi::mark_outbox_item_as_released( + CpiContext::new_with_signer( + self.manager.to_account_info(), + example_native_token_transfers::cpi::accounts::MarkOutboxItemAsReleased { + signer: self.outbox_item_signer.to_account_info(), + config: example_native_token_transfers::cpi::accounts::NotPausedConfig { + config: self.config.config.to_account_info(), + }, + outbox_item: self.outbox_item.to_account_info(), + transceiver: self.transceiver.to_account_info(), + }, + // signer seeds + &[&[OUTBOX_ITEM_SIGNER_SEED, &[bump_seed]]], + ), + )?; + Ok(result.get()) + } +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct ReleaseOutboundArgs { + pub revert_on_delay: bool, +} + +pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs) -> Result<()> { + let accs = ctx.accounts; + let released = accs.mark_outbox_item_as_released(ctx.bumps.outbox_item_signer)?; + + if !released { + if args.revert_on_delay { + return Err(NTTError::CantReleaseYet.into()); + } else { + return Ok(()); + } + } + + accs.outbox_item.reload()?; + assert!(accs.outbox_item.released.get(accs.transceiver.id)?); + + let message: TransceiverMessage> = + TransceiverMessage::new( + // TODO: should we just put the ntt id here statically? + accs.outbox_item.to_account_info().owner.to_bytes(), + accs.outbox_item.recipient_ntt_manager, + NttManagerMessage { + id: accs.outbox_item.key().to_bytes(), + sender: accs.outbox_item.sender.to_bytes(), + payload: NativeTokenTransfer { + amount: accs.outbox_item.amount, + source_token: accs.config.mint.to_bytes(), + to: accs.outbox_item.recipient_address, + to_chain: accs.outbox_item.recipient_chain, + additional_payload: Payload {}, + }, + }, + vec![], + ); + + post_message( + &accs.wormhole, + accs.payer.to_account_info(), + accs.wormhole_message.to_account_info(), + accs.emitter.to_account_info(), + ctx.bumps.emitter, + &message, + &[&[ + b"message", + accs.outbox_item.key().as_ref(), + &[ctx.bumps.wormhole_message], + ]], + )?; + + Ok(()) +} diff --git a/solana/programs/ntt-transceiver/src/wormhole/mod.rs b/solana/programs/ntt-transceiver/src/wormhole/mod.rs new file mode 100644 index 000000000..8c622be34 --- /dev/null +++ b/solana/programs/ntt-transceiver/src/wormhole/mod.rs @@ -0,0 +1,4 @@ +pub mod accounts; +pub mod instructions; + +pub use instructions::*; diff --git a/solana/programs/wormhole-governance/Cargo.toml b/solana/programs/wormhole-governance/Cargo.toml index 0d384e87e..e3607d1f4 100644 --- a/solana/programs/wormhole-governance/Cargo.toml +++ b/solana/programs/wormhole-governance/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wormhole-governance" -version = "2.0.0" +version = "3.0.0" description = "Governance for programs controlled by Wormhole Guardians" edition = "2021" diff --git a/solana/scripts/anchor-lint.sh b/solana/scripts/anchor-lint.sh index 3c18bdee7..f6678ad4b 100644 --- a/solana/scripts/anchor-lint.sh +++ b/solana/scripts/anchor-lint.sh @@ -3,7 +3,12 @@ set -uo pipefail SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) TARGET=${SCRIPT_DIR}/../programs -RESULTS=$(find "${TARGET}" -name "*.rs" -type f -exec anchor idl parse -o /dev/null --file {} \; 2>&1 | grep -v '^Error: Program module not found$') + +# Anchor IDL does not handle nested imports well (https://github.com/coral-xyz/anchor/issues/1099) +# This directory has a workaround for it but that is not recognized by idl parse - hence it is skipped +SKIP_DIR="${TARGET}/ntt-transceiver/src" + +RESULTS=$(find "${TARGET}" -path "${SKIP_DIR}" -prune -o -name "*.rs" -type f -exec anchor idl parse -o /dev/null --file {} \; 2>&1 | grep -v '^Error: Program module not found$') if [[ -n "$RESULTS" ]]; then echo "${RESULTS}" exit 1 diff --git a/solana/scripts/patch-idl b/solana/scripts/patch-idl index f356473f7..0f37f1320 100755 --- a/solana/scripts/patch-idl +++ b/solana/scripts/patch-idl @@ -9,5 +9,5 @@ if [ -z "$FILE" ]; then exit 1 fi -cat $FILE | jq '(.accounts, .types) |= map(select(has("generics") | not))' > temp.json && mv temp.json $FILE +cat $FILE | (jq '(.accounts, .types) |= map(select(has("generics") | not))' > temp.json 2>/dev/null && mv temp.json $FILE) || rm temp.json echo "Patched $FILE" diff --git a/solana/tests/anchor.test.ts b/solana/tests/anchor.test.ts index 7b162182b..16ba7319b 100644 --- a/solana/tests/anchor.test.ts +++ b/solana/tests/anchor.test.ts @@ -1,6 +1,7 @@ import * as anchor from "@coral-xyz/anchor"; import * as spl from "@solana/spl-token"; import { + AccountAddress, ChainAddress, ChainContext, Signer, @@ -13,7 +14,6 @@ import { serialize, serializePayload, signSendWait as ssw, - AccountAddress, } from "@wormhole-foundation/sdk"; import * as testing from "@wormhole-foundation/sdk-definitions/testing"; import { @@ -26,19 +26,25 @@ import * as fs from "fs"; import { PublicKey, - sendAndConfirmTransaction, SystemProgram, Transaction, + sendAndConfirmTransaction, } from "@solana/web3.js"; import { DummyTransferHook } from "../ts/idl/1_0_0/ts/dummy_transfer_hook.js"; +import { getTransceiverProgram, IdlVersion, NTT } from "../ts/index.js"; +import { derivePda } from "../ts/lib/utils.js"; import { SolanaNtt } from "../ts/sdk/index.js"; const solanaRootDir = `${__dirname}/../`; +const VERSION: IdlVersion = "3.0.0"; const GUARDIAN_KEY = "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"; const CORE_BRIDGE_ADDRESS = contracts.coreBridge("Mainnet", "Solana"); -const NTT_ADDRESS = anchor.workspace.ExampleNativeTokenTransfers.programId; +const NTT_ADDRESS: PublicKey = + anchor.workspace.ExampleNativeTokenTransfers.programId; +const WH_TRANSCEIVER_ADDRESS: PublicKey = + anchor.workspace.NttTransceiver.programId; async function signSendWait( chain: ChainContext, @@ -115,6 +121,14 @@ const coreBridge = new SolanaWormholeCore("Devnet", "Solana", connection, { coreBridge: CORE_BRIDGE_ADDRESS, }); +const nttTransceivers = { + wormhole: getTransceiverProgram( + connection, + WH_TRANSCEIVER_ADDRESS.toBase58(), + VERSION + ), +}; + const TOKEN_PROGRAM = spl.TOKEN_2022_PROGRAM_ID; describe("example-native-token-transfers", () => { @@ -192,21 +206,29 @@ describe("example-native-token-transfers", () => { tokenAddress = mint.publicKey.toBase58(); // Create our contract client - ntt = new SolanaNtt("Devnet", "Solana", connection, { - ...ctx.config.contracts, - ntt: { - token: tokenAddress, - manager: NTT_ADDRESS, - transceiver: { wormhole: NTT_ADDRESS }, + ntt = new SolanaNtt( + "Devnet", + "Solana", + connection, + { + ...ctx.config.contracts, + ntt: { + token: tokenAddress, + manager: NTT_ADDRESS.toBase58(), + transceiver: { + wormhole: nttTransceivers["wormhole"].programId.toBase58(), + }, + }, }, - }); + VERSION + ); } catch (e) { console.error("Failed to setup solana token: ", e); throw e; } }); - describe("Locking", () => { + describe("Burning", () => { beforeAll(async () => { try { await spl.setAuthority( @@ -230,10 +252,9 @@ describe("example-native-token-transfers", () => { await signSendWait(ctx, initTxs, signer); // register - const registerTxs = ntt.registerTransceiver({ + const registerTxs = ntt.registerWormholeTransceiver({ payer: new SolanaAddress(payer.publicKey), owner: new SolanaAddress(payer.publicKey), - transceiver: ntt.program.programId, }); await signSendWait(ctx, registerTxs, signer); @@ -299,9 +320,18 @@ describe("example-native-token-transfers", () => { ); await signSendWait(ctx, xferTxs, signer); - const wormholeMessage = ntt.pdas.wormholeMessageAccount( + // assert that released bitmap has transceiver bits set + const outboxItemInfo = await ntt.program.account.outboxItem.fetch( outboxItem.publicKey ); + expect(outboxItemInfo.released.map.bitLength()).toBe( + Object.keys(nttTransceivers).length + ); + + const wormholeMessage = derivePda( + ["message", outboxItem.publicKey.toBytes()], + nttTransceivers["wormhole"].programId + ); const unsignedVaa = await coreBridge.parsePostMessageAccount( wormholeMessage @@ -361,7 +391,6 @@ describe("example-native-token-transfers", () => { const published = emitter.publishMessage(0, serialized, 200); const rawVaa = guardians.addSignatures(published, [0]); const vaa = deserialize("Ntt:WormholeTransfer", serialize(rawVaa)); - const redeemTxs = ntt.redeem([vaa], sender); try { await signSendWait(ctx, redeemTxs, signer); @@ -370,7 +399,6 @@ describe("example-native-token-transfers", () => { throw e; } - // expect(released).toEqual(true); expect((await counterValue()).toString()).toEqual("2"); }); }); @@ -381,8 +409,10 @@ describe("example-native-token-transfers", () => { const overrides = { Solana: { token: tokenAddress, - manager: NTT_ADDRESS, - transceiver: { wormhole: NTT_ADDRESS }, + manager: NTT_ADDRESS.toBase58(), + transceiver: { + wormhole: nttTransceivers["wormhole"].programId.toBase58(), + }, }, }; @@ -414,7 +444,34 @@ describe("example-native-token-transfers", () => { { ntt: overrides["Solana"] }, new SolanaAddress(payer.publicKey.toBase58()) ); - expect(version).toBe("2.0.0"); + expect(version).toBe("3.0.0"); + }); + + test("It initializes using `emitterAccount` as transceiver address", async function () { + const overrideEmitter: (typeof overrides)["Solana"] = JSON.parse( + JSON.stringify(overrides["Solana"]) + ); + overrideEmitter.transceiver.wormhole = NTT.transceiverPdas(NTT_ADDRESS) + .emitterAccount() + .toBase58(); + + const ntt = new SolanaNtt("Devnet", "Solana", connection, { + ...ctx.config.contracts, + ...{ ntt: overrideEmitter }, + }); + expect(ntt).toBeTruthy(); + }); + + test("It gets the correct transceiver type", async function () { + const ntt = new SolanaNtt("Devnet", "Solana", connection, { + ...ctx.config.contracts, + ...{ ntt: overrides["Solana"] }, + }); + const whTransceiver = await ntt.getWormholeTransceiver(); + const transceiverType = await whTransceiver!.getTransceiverType( + new SolanaAddress(payer.publicKey.toBase58()) + ); + expect(transceiverType).toBe("wormhole"); }); }); }); diff --git a/solana/ts/idl/2_0_0/json/example_native_token_transfers.json b/solana/ts/idl/2_0_0/json/example_native_token_transfers.json index b33eb8a1b..8883c0024 100644 --- a/solana/ts/idl/2_0_0/json/example_native_token_transfers.json +++ b/solana/ts/idl/2_0_0/json/example_native_token_transfers.json @@ -61,9 +61,7 @@ "name": "tokenProgram", "isMut": false, "isSigner": false, - "docs": [ - "associated token account for the given mint." - ] + "docs": ["associated token account for the given mint."] }, { "name": "associatedTokenProgram", @@ -242,9 +240,7 @@ "name": "from", "isMut": true, "isSigner": false, - "docs": [ - "account can spend these tokens." - ] + "docs": ["account can spend these tokens."] }, { "name": "tokenProgram", @@ -341,9 +337,7 @@ "name": "from", "isMut": true, "isSigner": false, - "docs": [ - "account can spend these tokens." - ] + "docs": ["account can spend these tokens."] }, { "name": "tokenProgram", @@ -426,7 +420,10 @@ { "name": "transceiverMessage", "isMut": false, - "isSigner": false + "isSigner": false, + "docs": [ + "`Account` and `owner` constraints are mutually-exclusive" + ] }, { "name": "transceiver", @@ -766,9 +763,7 @@ "name": "transceiver", "isMut": false, "isSigner": false, - "docs": [ - "used here that wraps the Transceiver account type." - ] + "docs": ["used here that wraps the Transceiver account type."] }, { "name": "registeredTransceiver", @@ -1168,25 +1163,19 @@ }, { "name": "owner", - "docs": [ - "Owner of the program." - ], + "docs": ["Owner of the program."], "type": "publicKey" }, { "name": "pendingOwner", - "docs": [ - "Pending next owner (before claiming ownership)." - ], + "docs": ["Pending next owner (before claiming ownership)."], "type": { "option": "publicKey" } }, { "name": "mint", - "docs": [ - "Mint address of the token managed by this program." - ], + "docs": ["Mint address of the token managed by this program."], "type": "publicKey" }, { @@ -1253,9 +1242,7 @@ }, { "name": "custody", - "docs": [ - "The custody account that holds tokens in locking mode." - ], + "docs": ["The custody account that holds tokens in locking mode."], "type": "publicKey" } ] @@ -1292,10 +1279,7 @@ { "name": "address", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } }, { @@ -1387,19 +1371,13 @@ { "name": "recipientNttManager", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } }, { "name": "recipientAddress", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } }, { @@ -1464,10 +1442,7 @@ { "name": "address", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } } ] @@ -1487,9 +1462,7 @@ }, { "name": "lastLamports", - "docs": [ - "Lamports in the collection account" - ], + "docs": ["Lamports in the collection account"], "type": "u64" }, { @@ -1562,10 +1535,7 @@ { "name": "address", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } }, { @@ -1574,9 +1544,7 @@ }, { "name": "tokenDecimals", - "docs": [ - "The token decimals on the peer chain." - ], + "docs": ["The token decimals on the peer chain."], "type": "u8" } ] @@ -1641,10 +1609,7 @@ { "name": "recipientAddress", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } }, { @@ -1670,9 +1635,7 @@ }, { "name": "ReleaseAfter", - "fields": [ - "i64" - ] + "fields": ["i64"] }, { "name": "Released" @@ -1687,9 +1650,7 @@ "fields": [ { "name": "limit", - "docs": [ - "The maximum capacity of the rate limiter." - ], + "docs": ["The maximum capacity of the rate limiter."], "type": "u64" }, { @@ -1728,10 +1689,7 @@ { "name": "address", "type": { - "array": [ - "u8", - 32 - ] + "array": ["u8", 32] } } ] diff --git a/solana/ts/idl/2_0_0/json/ntt_quoter.json b/solana/ts/idl/2_0_0/json/ntt_quoter.json index d6c6f2f7a..add9be2c2 100644 --- a/solana/ts/idl/2_0_0/json/ntt_quoter.json +++ b/solana/ts/idl/2_0_0/json/ntt_quoter.json @@ -29,9 +29,7 @@ "name": "outboxItem", "isMut": false, "isSigner": false, - "docs": [ - "and checking the release constraint into a single function" - ] + "docs": ["and checking the release constraint into a single function"] }, { "name": "relayRequest", @@ -585,4 +583,4 @@ "msg": "The price cannot be zero" } ] -} \ No newline at end of file +} diff --git a/solana/ts/idl/2_0_0/ts/example_native_token_transfers.ts b/solana/ts/idl/2_0_0/ts/example_native_token_transfers.ts index 29d494549..0b8810579 100644 --- a/solana/ts/idl/2_0_0/ts/example_native_token_transfers.ts +++ b/solana/ts/idl/2_0_0/ts/example_native_token_transfers.ts @@ -1,3907 +1,3818 @@ export type ExampleNativeTokenTransfers = { - "version": "2.0.0", - "name": "example_native_token_transfers", - "instructions": [ + version: "2.0.0"; + name: "example_native_token_transfers"; + instructions: [ { - "name": "initialize", - "accounts": [ + name: "initialize"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "deployer", - "isMut": false, - "isSigner": true + name: "deployer"; + isMut: false; + isSigner: true; }, { - "name": "programData", - "isMut": false, - "isSigner": false + name: "programData"; + isMut: false; + isSigner: false; }, { - "name": "config", - "isMut": true, - "isSigner": false + name: "config"; + isMut: true; + isSigner: false; }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint"; + isMut: false; + isSigner: false; }, { - "name": "rateLimit", - "isMut": true, - "isSigner": false + name: "rateLimit"; + isMut: true; + isSigner: false; }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false, - "docs": [ + name: "tokenAuthority"; + isMut: false; + isSigner: false; + docs: [ "In any case, this function is used to set the Config and initialize the program so we", "assume the caller of this function will have total control over the program.", "", - "TODO: Using `UncheckedAccount` here leads to \"Access violation in stack frame ...\".", + 'TODO: Using `UncheckedAccount` here leads to "Access violation in stack frame ...".', "Could refactor code to use `Box<_>` to reduce stack size." - ] + ]; }, { - "name": "custody", - "isMut": true, - "isSigner": false, - "docs": [ + name: "custody"; + isMut: true; + isSigner: false; + docs: [ "The custody account that holds tokens in locking mode and temporarily", "holds tokens in burning mode.", "function if the token account has already been created." - ] + ]; }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "associated token account for the given mint." - ] + name: "tokenProgram"; + isMut: false; + isSigner: false; + docs: ["associated token account for the given mint."]; }, { - "name": "associatedTokenProgram", - "isMut": false, - "isSigner": false + name: "associatedTokenProgram"; + isMut: false; + isSigner: false; }, { - "name": "bpfLoaderUpgradeableProgram", - "isMut": false, - "isSigner": false + name: "bpfLoaderUpgradeableProgram"; + isMut: false; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "InitializeArgs" - } + name: "args"; + type: { + defined: "InitializeArgs"; + }; } - ] + ]; }, { - "name": "initializeLut", - "accounts": [ + name: "initializeLut"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "authority", - "isMut": false, - "isSigner": false + name: "authority"; + isMut: false; + isSigner: false; }, { - "name": "lutAddress", - "isMut": true, - "isSigner": false + name: "lutAddress"; + isMut: true; + isSigner: false; }, { - "name": "lut", - "isMut": true, - "isSigner": false + name: "lut"; + isMut: true; + isSigner: false; }, { - "name": "lutProgram", - "isMut": false, - "isSigner": false + name: "lutProgram"; + isMut: false; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; }, { - "name": "entries", - "accounts": [ + name: "entries"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "custody", - "isMut": false, - "isSigner": false + name: "custody"; + isMut: false; + isSigner: false; }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram"; + isMut: false; + isSigner: false; }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint"; + isMut: false; + isSigner: false; }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false + name: "tokenAuthority"; + isMut: false; + isSigner: false; }, { - "name": "outboxRateLimit", - "isMut": false, - "isSigner": false + name: "outboxRateLimit"; + isMut: false; + isSigner: false; }, { - "name": "wormhole", - "accounts": [ + name: "wormhole"; + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge"; + isMut: true; + isSigner: false; }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector"; + isMut: true; + isSigner: false; }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence"; + isMut: true; + isSigner: false; }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program"; + isMut: false; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock"; + isMut: false; + isSigner: false; }, { - "name": "rent", - "isMut": false, - "isSigner": false + name: "rent"; + isMut: false; + isSigner: false; } - ] + ]; } - ] + ]; } - ], - "args": [ + ]; + args: [ { - "name": "recentSlot", - "type": "u64" + name: "recentSlot"; + type: "u64"; } - ] + ]; }, { - "name": "version", - "accounts": [], - "args": [], - "returns": "string" + name: "version"; + accounts: []; + args: []; + returns: "string"; }, { - "name": "transferBurn", - "accounts": [ + name: "transferBurn"; + accounts: [ { - "name": "common", - "accounts": [ + name: "common"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "accounts": [ + name: "config"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint"; + isMut: true; + isSigner: false; }, { - "name": "from", - "isMut": true, - "isSigner": false, - "docs": [ - "account can spend these tokens." - ] + name: "from"; + isMut: true; + isSigner: false; + docs: ["account can spend these tokens."]; }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram"; + isMut: false; + isSigner: false; }, { - "name": "outboxItem", - "isMut": true, - "isSigner": true + name: "outboxItem"; + isMut: true; + isSigner: true; }, { - "name": "outboxRateLimit", - "isMut": true, - "isSigner": false + name: "outboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "custody", - "isMut": true, - "isSigner": false, - "docs": [ + name: "custody"; + isMut: true; + isSigner: false; + docs: [ "Tokens are always transferred to the custody account first regardless of", "the mode.", "For an explanation, see the note in [`transfer_burn`]." - ] + ]; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer"; + isMut: false; + isSigner: false; }, { - "name": "sessionAuthority", - "isMut": false, - "isSigner": false, - "docs": [ + name: "sessionAuthority"; + isMut: false; + isSigner: false; + docs: [ "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." - ] + ]; }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false + name: "tokenAuthority"; + isMut: false; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "TransferArgs" - } + name: "args"; + type: { + defined: "TransferArgs"; + }; } - ] + ]; }, { - "name": "transferLock", - "accounts": [ + name: "transferLock"; + accounts: [ { - "name": "common", - "accounts": [ + name: "common"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "accounts": [ + name: "config"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint"; + isMut: true; + isSigner: false; }, { - "name": "from", - "isMut": true, - "isSigner": false, - "docs": [ - "account can spend these tokens." - ] + name: "from"; + isMut: true; + isSigner: false; + docs: ["account can spend these tokens."]; }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram"; + isMut: false; + isSigner: false; }, { - "name": "outboxItem", - "isMut": true, - "isSigner": true + name: "outboxItem"; + isMut: true; + isSigner: true; }, { - "name": "outboxRateLimit", - "isMut": true, - "isSigner": false + name: "outboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "custody", - "isMut": true, - "isSigner": false, - "docs": [ + name: "custody"; + isMut: true; + isSigner: false; + docs: [ "Tokens are always transferred to the custody account first regardless of", "the mode.", "For an explanation, see the note in [`transfer_burn`]." - ] + ]; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer"; + isMut: false; + isSigner: false; }, { - "name": "sessionAuthority", - "isMut": false, - "isSigner": false, - "docs": [ + name: "sessionAuthority"; + isMut: false; + isSigner: false; + docs: [ "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." - ] + ]; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "TransferArgs" - } + name: "args"; + type: { + defined: "TransferArgs"; + }; } - ] + ]; }, { - "name": "redeem", - "accounts": [ + name: "redeem"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer"; + isMut: false; + isSigner: false; }, { - "name": "transceiverMessage", - "isMut": false, - "isSigner": false + name: "transceiverMessage"; + isMut: false; + isSigner: false; + docs: ["`Account` and `owner` constraints are mutually-exclusive"]; }, { - "name": "transceiver", - "isMut": false, - "isSigner": false + name: "transceiver"; + isMut: false; + isSigner: false; }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint"; + isMut: false; + isSigner: false; }, { - "name": "inboxItem", - "isMut": true, - "isSigner": false, - "docs": [ + name: "inboxItem"; + isMut: true; + isSigner: false; + docs: [ "NOTE: This account is content-addressed (PDA seeded by the message hash).", "This is because in a multi-transceiver configuration, the different", - "transceivers \"vote\" on messages (by delivering them). By making the inbox", + 'transceivers "vote" on messages (by delivering them). By making the inbox', "items content-addressed, we can ensure that disagreeing votes don't", "interfere with each other.", "On the first call to [`redeem()`], [`InboxItem`] will be allocated and initialized with", "default values.", - "On subsequent calls, we want to modify the `InboxItem` by \"voting\" on it. Therefore the", + 'On subsequent calls, we want to modify the `InboxItem` by "voting" on it. Therefore the', "program should not fail which would occur when using the `init` constraint.", "The [`InboxItem::init`] field is used to guard against malicious or accidental modification", "InboxItem fields that should remain constant." - ] + ]; }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "outboxRateLimit", - "isMut": true, - "isSigner": false + name: "outboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "RedeemArgs" - } + name: "args"; + type: { + defined: "RedeemArgs"; + }; } - ] + ]; }, { - "name": "releaseInboundMint", - "accounts": [ + name: "releaseInboundMint"; + accounts: [ { - "name": "common", - "accounts": [ + name: "common"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "accounts": [ + name: "config"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "inboxItem", - "isMut": true, - "isSigner": false + name: "inboxItem"; + isMut: true; + isSigner: false; }, { - "name": "recipient", - "isMut": true, - "isSigner": false + name: "recipient"; + isMut: true; + isSigner: false; }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false, - "docs": [ + name: "tokenAuthority"; + isMut: false; + isSigner: false; + docs: [ "CHECK The seeds constraint ensures that this is the correct address" - ] + ]; }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint"; + isMut: true; + isSigner: false; }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram"; + isMut: false; + isSigner: false; }, { - "name": "custody", - "isMut": true, - "isSigner": false + name: "custody"; + isMut: true; + isSigner: false; } - ] + ]; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "ReleaseInboundArgs" - } + name: "args"; + type: { + defined: "ReleaseInboundArgs"; + }; } - ] + ]; }, { - "name": "releaseInboundUnlock", - "accounts": [ + name: "releaseInboundUnlock"; + accounts: [ { - "name": "common", - "accounts": [ + name: "common"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "accounts": [ + name: "config"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "inboxItem", - "isMut": true, - "isSigner": false + name: "inboxItem"; + isMut: true; + isSigner: false; }, { - "name": "recipient", - "isMut": true, - "isSigner": false + name: "recipient"; + isMut: true; + isSigner: false; }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false, - "docs": [ + name: "tokenAuthority"; + isMut: false; + isSigner: false; + docs: [ "CHECK The seeds constraint ensures that this is the correct address" - ] + ]; }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint"; + isMut: true; + isSigner: false; }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram"; + isMut: false; + isSigner: false; }, { - "name": "custody", - "isMut": true, - "isSigner": false + name: "custody"; + isMut: true; + isSigner: false; } - ] + ]; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "ReleaseInboundArgs" - } + name: "args"; + type: { + defined: "ReleaseInboundArgs"; + }; } - ] + ]; }, { - "name": "transferOwnership", - "accounts": [ + name: "transferOwnership"; + accounts: [ { - "name": "config", - "isMut": true, - "isSigner": false + name: "config"; + isMut: true; + isSigner: false; }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "newOwner", - "isMut": false, - "isSigner": false + name: "newOwner"; + isMut: false; + isSigner: false; }, { - "name": "upgradeLock", - "isMut": false, - "isSigner": false + name: "upgradeLock"; + isMut: false; + isSigner: false; }, { - "name": "programData", - "isMut": true, - "isSigner": false + name: "programData"; + isMut: true; + isSigner: false; }, { - "name": "bpfLoaderUpgradeableProgram", - "isMut": false, - "isSigner": false + name: "bpfLoaderUpgradeableProgram"; + isMut: false; + isSigner: false; } - ], - "args": [] + ]; + args: []; }, { - "name": "claimOwnership", - "accounts": [ + name: "claimOwnership"; + accounts: [ { - "name": "config", - "isMut": true, - "isSigner": false + name: "config"; + isMut: true; + isSigner: false; }, { - "name": "upgradeLock", - "isMut": false, - "isSigner": false + name: "upgradeLock"; + isMut: false; + isSigner: false; }, { - "name": "newOwner", - "isMut": false, - "isSigner": true + name: "newOwner"; + isMut: false; + isSigner: true; }, { - "name": "programData", - "isMut": true, - "isSigner": false + name: "programData"; + isMut: true; + isSigner: false; }, { - "name": "bpfLoaderUpgradeableProgram", - "isMut": false, - "isSigner": false + name: "bpfLoaderUpgradeableProgram"; + isMut: false; + isSigner: false; } - ], - "args": [] + ]; + args: []; }, { - "name": "setPaused", - "accounts": [ + name: "setPaused"; + accounts: [ { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "config", - "isMut": true, - "isSigner": false + name: "config"; + isMut: true; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "pause", - "type": "bool" + name: "pause"; + type: "bool"; } - ] + ]; }, { - "name": "setPeer", - "accounts": [ + name: "setPeer"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "peer", - "isMut": true, - "isSigner": false + name: "peer"; + isMut: true; + isSigner: false; }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit"; + isMut: true; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "SetPeerArgs" - } + name: "args"; + type: { + defined: "SetPeerArgs"; + }; } - ] + ]; }, { - "name": "registerTransceiver", - "accounts": [ + name: "registerTransceiver"; + accounts: [ { - "name": "config", - "isMut": true, - "isSigner": false + name: "config"; + isMut: true; + isSigner: false; }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "transceiver", - "isMut": false, - "isSigner": false, - "docs": [ - "used here that wraps the Transceiver account type." - ] + name: "transceiver"; + isMut: false; + isSigner: false; + docs: ["used here that wraps the Transceiver account type."]; }, { - "name": "registeredTransceiver", - "isMut": true, - "isSigner": false + name: "registeredTransceiver"; + isMut: true; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ], - "args": [] + ]; + args: []; }, { - "name": "setOutboundLimit", - "accounts": [ + name: "setOutboundLimit"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "rateLimit", - "isMut": true, - "isSigner": false + name: "rateLimit"; + isMut: true; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "SetOutboundLimitArgs" - } + name: "args"; + type: { + defined: "SetOutboundLimitArgs"; + }; } - ] + ]; }, { - "name": "setInboundLimit", - "accounts": [ + name: "setInboundLimit"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "rateLimit", - "isMut": true, - "isSigner": false + name: "rateLimit"; + isMut: true; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "SetInboundLimitArgs" - } + name: "args"; + type: { + defined: "SetInboundLimitArgs"; + }; } - ] + ]; }, { - "name": "setWormholePeer", - "accounts": [ + name: "setWormholePeer"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner"; + isMut: false; + isSigner: true; }, { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "peer", - "isMut": true, - "isSigner": false + name: "peer"; + isMut: true; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "SetTransceiverPeerArgs" - } + name: "args"; + type: { + defined: "SetTransceiverPeerArgs"; + }; } - ] + ]; }, { - "name": "receiveWormholeMessage", - "accounts": [ + name: "receiveWormholeMessage"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "accounts": [ + name: "config"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer"; + isMut: false; + isSigner: false; }, { - "name": "vaa", - "isMut": false, - "isSigner": false + name: "vaa"; + isMut: false; + isSigner: false; }, { - "name": "transceiverMessage", - "isMut": true, - "isSigner": false + name: "transceiverMessage"; + isMut: true; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; } - ], - "args": [] + ]; + args: []; }, { - "name": "releaseWormholeOutbound", - "accounts": [ + name: "releaseWormholeOutbound"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "accounts": [ + name: "config"; + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; } - ] + ]; }, { - "name": "outboxItem", - "isMut": true, - "isSigner": false + name: "outboxItem"; + isMut: true; + isSigner: false; }, { - "name": "transceiver", - "isMut": false, - "isSigner": false + name: "transceiver"; + isMut: false; + isSigner: false; }, { - "name": "wormholeMessage", - "isMut": true, - "isSigner": false + name: "wormholeMessage"; + isMut: true; + isSigner: false; }, { - "name": "emitter", - "isMut": false, - "isSigner": false + name: "emitter"; + isMut: false; + isSigner: false; }, { - "name": "wormhole", - "accounts": [ + name: "wormhole"; + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge"; + isMut: true; + isSigner: false; }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector"; + isMut: true; + isSigner: false; }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence"; + isMut: true; + isSigner: false; }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program"; + isMut: false; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock"; + isMut: false; + isSigner: false; }, { - "name": "rent", - "isMut": false, - "isSigner": false + name: "rent"; + isMut: false; + isSigner: false; } - ] + ]; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "ReleaseOutboundArgs" - } + name: "args"; + type: { + defined: "ReleaseOutboundArgs"; + }; } - ] + ]; }, { - "name": "broadcastWormholeId", - "accounts": [ + name: "broadcastWormholeId"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint"; + isMut: false; + isSigner: false; }, { - "name": "wormholeMessage", - "isMut": true, - "isSigner": true + name: "wormholeMessage"; + isMut: true; + isSigner: true; }, { - "name": "emitter", - "isMut": false, - "isSigner": false + name: "emitter"; + isMut: false; + isSigner: false; }, { - "name": "wormhole", - "accounts": [ + name: "wormhole"; + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge"; + isMut: true; + isSigner: false; }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector"; + isMut: true; + isSigner: false; }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence"; + isMut: true; + isSigner: false; }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program"; + isMut: false; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock"; + isMut: false; + isSigner: false; }, { - "name": "rent", - "isMut": false, - "isSigner": false + name: "rent"; + isMut: false; + isSigner: false; } - ] + ]; } - ], - "args": [] + ]; + args: []; }, { - "name": "broadcastWormholePeer", - "accounts": [ + name: "broadcastWormholePeer"; + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer"; + isMut: true; + isSigner: true; }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config"; + isMut: false; + isSigner: false; }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer"; + isMut: false; + isSigner: false; }, { - "name": "wormholeMessage", - "isMut": true, - "isSigner": true + name: "wormholeMessage"; + isMut: true; + isSigner: true; }, { - "name": "emitter", - "isMut": false, - "isSigner": false + name: "emitter"; + isMut: false; + isSigner: false; }, { - "name": "wormhole", - "accounts": [ + name: "wormhole"; + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge"; + isMut: true; + isSigner: false; }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector"; + isMut: true; + isSigner: false; }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence"; + isMut: true; + isSigner: false; }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program"; + isMut: false; + isSigner: false; }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram"; + isMut: false; + isSigner: false; }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock"; + isMut: false; + isSigner: false; }, { - "name": "rent", - "isMut": false, - "isSigner": false + name: "rent"; + isMut: false; + isSigner: false; } - ] + ]; } - ], - "args": [ + ]; + args: [ { - "name": "args", - "type": { - "defined": "BroadcastPeerArgs" - } + name: "args"; + type: { + defined: "BroadcastPeerArgs"; + }; } - ] + ]; } - ], - "accounts": [ + ]; + accounts: [ { - "name": "config", - "type": { - "kind": "struct", - "fields": [ + name: "config"; + type: { + kind: "struct"; + fields: [ { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "owner", - "docs": [ - "Owner of the program." - ], - "type": "publicKey" + name: "owner"; + docs: ["Owner of the program."]; + type: "publicKey"; }, { - "name": "pendingOwner", - "docs": [ - "Pending next owner (before claiming ownership)." - ], - "type": { - "option": "publicKey" - } + name: "pendingOwner"; + docs: ["Pending next owner (before claiming ownership)."]; + type: { + option: "publicKey"; + }; }, { - "name": "mint", - "docs": [ - "Mint address of the token managed by this program." - ], - "type": "publicKey" + name: "mint"; + docs: ["Mint address of the token managed by this program."]; + type: "publicKey"; }, { - "name": "tokenProgram", - "docs": [ + name: "tokenProgram"; + docs: [ "Address of the token program (token or token22). This could always be queried", "from the [`mint`] account's owner, but storing it here avoids an indirection", "on the client side." - ], - "type": "publicKey" + ]; + type: "publicKey"; }, { - "name": "mode", - "docs": [ + name: "mode"; + docs: [ "The mode that this program is running in. This is used to determine", "whether the program is burning tokens or locking tokens." - ], - "type": { - "defined": "Mode" - } + ]; + type: { + defined: "Mode"; + }; }, { - "name": "chainId", - "docs": [ + name: "chainId"; + docs: [ "The chain id of the chain that this program is running on. We don't", "hardcode this so that the program is deployable on any potential SVM", "forks." - ], - "type": { - "defined": "ChainId" - } + ]; + type: { + defined: "ChainId"; + }; }, { - "name": "nextTransceiverId", - "docs": [ + name: "nextTransceiverId"; + docs: [ "The next transceiver id to use when registering an transceiver." - ], - "type": "u8" + ]; + type: "u8"; }, { - "name": "threshold", - "docs": [ + name: "threshold"; + docs: [ "The number of transceivers that must attest to a transfer before it is", "accepted." - ], - "type": "u8" + ]; + type: "u8"; }, { - "name": "enabledTransceivers", - "docs": [ + name: "enabledTransceivers"; + docs: [ "Bitmap of enabled transceivers.", "The maximum number of transceivers is equal to [`Bitmap::BITS`]." - ], - "type": { - "defined": "Bitmap" - } + ]; + type: { + defined: "Bitmap"; + }; }, { - "name": "paused", - "docs": [ + name: "paused"; + docs: [ "Pause the program. This is useful for upgrades and other maintenance." - ], - "type": "bool" + ]; + type: "bool"; }, { - "name": "custody", - "docs": [ - "The custody account that holds tokens in locking mode." - ], - "type": "publicKey" + name: "custody"; + docs: ["The custody account that holds tokens in locking mode."]; + type: "publicKey"; } - ] - } + ]; + }; }, { - "name": "LUT", - "type": { - "kind": "struct", - "fields": [ + name: "LUT"; + type: { + kind: "struct"; + fields: [ { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "address", - "type": "publicKey" + name: "address"; + type: "publicKey"; } - ] - } + ]; + }; }, { - "name": "nttManagerPeer", - "docs": [ + name: "nttManagerPeer"; + docs: [ "A peer on another chain. Stored in a PDA seeded by the chain id." - ], - "type": { - "kind": "struct", - "fields": [ + ]; + type: { + kind: "struct"; + fields: [ { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "address"; + type: { + array: ["u8", 32]; + }; }, { - "name": "tokenDecimals", - "type": "u8" + name: "tokenDecimals"; + type: "u8"; } - ] - } + ]; + }; }, { - "name": "inboxItem", - "type": { - "kind": "struct", - "fields": [ + name: "inboxItem"; + type: { + kind: "struct"; + fields: [ { - "name": "init", - "type": "bool" + name: "init"; + type: "bool"; }, { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "amount", - "type": "u64" + name: "amount"; + type: "u64"; }, { - "name": "recipientAddress", - "type": "publicKey" + name: "recipientAddress"; + type: "publicKey"; }, { - "name": "votes", - "type": { - "defined": "Bitmap" - } + name: "votes"; + type: { + defined: "Bitmap"; + }; }, { - "name": "releaseStatus", - "type": { - "defined": "ReleaseStatus" - } + name: "releaseStatus"; + type: { + defined: "ReleaseStatus"; + }; } - ] - } + ]; + }; }, { - "name": "inboxRateLimit", - "docs": [ + name: "inboxRateLimit"; + docs: [ "Inbound rate limit per chain.", "SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.)" - ], - "type": { - "kind": "struct", - "fields": [ + ]; + type: { + kind: "struct"; + fields: [ { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "rateLimit", - "type": { - "defined": "RateLimitState" - } + name: "rateLimit"; + type: { + defined: "RateLimitState"; + }; } - ] - } + ]; + }; }, { - "name": "outboxItem", - "type": { - "kind": "struct", - "fields": [ + name: "outboxItem"; + type: { + kind: "struct"; + fields: [ { - "name": "amount", - "type": { - "defined": "TrimmedAmount" - } + name: "amount"; + type: { + defined: "TrimmedAmount"; + }; }, { - "name": "sender", - "type": "publicKey" + name: "sender"; + type: "publicKey"; }, { - "name": "recipientChain", - "type": { - "defined": "ChainId" - } + name: "recipientChain"; + type: { + defined: "ChainId"; + }; }, { - "name": "recipientNttManager", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "recipientNttManager"; + type: { + array: ["u8", 32]; + }; }, { - "name": "recipientAddress", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "recipientAddress"; + type: { + array: ["u8", 32]; + }; }, { - "name": "releaseTimestamp", - "type": "i64" + name: "releaseTimestamp"; + type: "i64"; }, { - "name": "released", - "type": { - "defined": "Bitmap" - } + name: "released"; + type: { + defined: "Bitmap"; + }; } - ] - } + ]; + }; }, { - "name": "outboxRateLimit", - "type": { - "kind": "struct", - "fields": [ + name: "outboxRateLimit"; + type: { + kind: "struct"; + fields: [ { - "name": "rateLimit", - "type": { - "defined": "RateLimitState" - } + name: "rateLimit"; + type: { + defined: "RateLimitState"; + }; } - ] - } + ]; + }; }, { - "name": "registeredTransceiver", - "type": { - "kind": "struct", - "fields": [ + name: "registeredTransceiver"; + type: { + kind: "struct"; + fields: [ { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "id", - "type": "u8" + name: "id"; + type: "u8"; }, { - "name": "transceiverAddress", - "type": "publicKey" + name: "transceiverAddress"; + type: "publicKey"; } - ] - } + ]; + }; }, { - "name": "transceiverPeer", - "docs": [ + name: "transceiverPeer"; + docs: [ "A peer on another chain. Stored in a PDA seeded by the chain id." - ], - "type": { - "kind": "struct", - "fields": [ + ]; + type: { + kind: "struct"; + fields: [ { - "name": "bump", - "type": "u8" + name: "bump"; + type: "u8"; }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "address"; + type: { + array: ["u8", 32]; + }; } - ] - } + ]; + }; }, { - "name": "bridgeData", - "type": { - "kind": "struct", - "fields": [ + name: "bridgeData"; + type: { + kind: "struct"; + fields: [ { - "name": "guardianSetIndex", - "docs": [ + name: "guardianSetIndex"; + docs: [ "The current guardian set index, used to decide which signature sets to accept." - ], - "type": "u32" + ]; + type: "u32"; }, { - "name": "lastLamports", - "docs": [ - "Lamports in the collection account" - ], - "type": "u64" + name: "lastLamports"; + docs: ["Lamports in the collection account"]; + type: "u64"; }, { - "name": "config", - "docs": [ + name: "config"; + docs: [ "Bridge configuration, which is set once upon initialization." - ], - "type": { - "defined": "BridgeConfig" - } + ]; + type: { + defined: "BridgeConfig"; + }; } - ] - } + ]; + }; } - ], - "types": [ + ]; + types: [ { - "name": "Bitmap", - "type": { - "kind": "struct", - "fields": [ + name: "Bitmap"; + type: { + kind: "struct"; + fields: [ { - "name": "map", - "type": "u128" + name: "map"; + type: "u128"; } - ] - } + ]; + }; }, { - "name": "SetInboundLimitArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetInboundLimitArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "limit", - "type": "u64" + name: "limit"; + type: "u64"; }, { - "name": "chainId", - "type": { - "defined": "ChainId" - } + name: "chainId"; + type: { + defined: "ChainId"; + }; } - ] - } + ]; + }; }, { - "name": "SetOutboundLimitArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetOutboundLimitArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "limit", - "type": "u64" + name: "limit"; + type: "u64"; } - ] - } + ]; + }; }, { - "name": "SetPeerArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetPeerArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "chainId", - "type": { - "defined": "ChainId" - } + name: "chainId"; + type: { + defined: "ChainId"; + }; }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "address"; + type: { + array: ["u8", 32]; + }; }, { - "name": "limit", - "type": "u64" + name: "limit"; + type: "u64"; }, { - "name": "tokenDecimals", - "docs": [ - "The token decimals on the peer chain." - ], - "type": "u8" + name: "tokenDecimals"; + docs: ["The token decimals on the peer chain."]; + type: "u8"; } - ] - } + ]; + }; }, { - "name": "InitializeArgs", - "type": { - "kind": "struct", - "fields": [ + name: "InitializeArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "chainId", - "type": "u16" + name: "chainId"; + type: "u16"; }, { - "name": "limit", - "type": "u64" + name: "limit"; + type: "u64"; }, { - "name": "mode", - "type": { - "defined": "Mode" - } + name: "mode"; + type: { + defined: "Mode"; + }; } - ] - } + ]; + }; }, { - "name": "RedeemArgs", - "type": { - "kind": "struct", - "fields": [] - } + name: "RedeemArgs"; + type: { + kind: "struct"; + fields: []; + }; }, { - "name": "ReleaseInboundArgs", - "type": { - "kind": "struct", - "fields": [ + name: "ReleaseInboundArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "revertOnDelay", - "type": "bool" + name: "revertOnDelay"; + type: "bool"; } - ] - } + ]; + }; }, { - "name": "TransferArgs", - "type": { - "kind": "struct", - "fields": [ + name: "TransferArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "amount", - "type": "u64" + name: "amount"; + type: "u64"; }, { - "name": "recipientChain", - "type": { - "defined": "ChainId" - } + name: "recipientChain"; + type: { + defined: "ChainId"; + }; }, { - "name": "recipientAddress", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "recipientAddress"; + type: { + array: ["u8", 32]; + }; }, { - "name": "shouldQueue", - "type": "bool" + name: "shouldQueue"; + type: "bool"; } - ] - } + ]; + }; }, { - "name": "ReleaseStatus", - "docs": [ + name: "ReleaseStatus"; + docs: [ "The status of an InboxItem. This determines whether the tokens are minted/unlocked to the recipient. As", "such, this must be used as a state machine that moves forward in a linear manner. A state", - "should never \"move backward\" to a previous state (e.g. should never move from `Released` to", + 'should never "move backward" to a previous state (e.g. should never move from `Released` to', "`ReleaseAfter`)." - ], - "type": { - "kind": "enum", - "variants": [ + ]; + type: { + kind: "enum"; + variants: [ { - "name": "NotApproved" + name: "NotApproved"; }, { - "name": "ReleaseAfter", - "fields": [ - "i64" - ] + name: "ReleaseAfter"; + fields: ["i64"]; }, { - "name": "Released" + name: "Released"; } - ] - } + ]; + }; }, { - "name": "RateLimitState", - "type": { - "kind": "struct", - "fields": [ + name: "RateLimitState"; + type: { + kind: "struct"; + fields: [ { - "name": "limit", - "docs": [ - "The maximum capacity of the rate limiter." - ], - "type": "u64" + name: "limit"; + docs: ["The maximum capacity of the rate limiter."]; + type: "u64"; }, { - "name": "capacityAtLastTx", - "docs": [ + name: "capacityAtLastTx"; + docs: [ "The capacity of the rate limiter at `last_tx_timestamp`.", "The actual current capacity is calculated in `capacity_at`, by", "accounting for the time that has passed since `last_tx_timestamp` and", "the refill rate." - ], - "type": "u64" + ]; + type: "u64"; }, { - "name": "lastTxTimestamp", - "docs": [ + name: "lastTxTimestamp"; + docs: [ "The timestamp of the last transaction that counted towards the current", "capacity. Transactions that exceeded the capacity do not count, they are", "just delayed." - ], - "type": "i64" + ]; + type: "i64"; } - ] - } + ]; + }; }, { - "name": "SetTransceiverPeerArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetTransceiverPeerArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "chainId", - "type": { - "defined": "ChainId" - } + name: "chainId"; + type: { + defined: "ChainId"; + }; }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "address"; + type: { + array: ["u8", 32]; + }; } - ] - } + ]; + }; }, { - "name": "BroadcastPeerArgs", - "type": { - "kind": "struct", - "fields": [ + name: "BroadcastPeerArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "chainId", - "type": "u16" + name: "chainId"; + type: "u16"; } - ] - } + ]; + }; }, { - "name": "ReleaseOutboundArgs", - "type": { - "kind": "struct", - "fields": [ + name: "ReleaseOutboundArgs"; + type: { + kind: "struct"; + fields: [ { - "name": "revertOnDelay", - "type": "bool" + name: "revertOnDelay"; + type: "bool"; } - ] - } + ]; + }; }, { - "name": "ChainId", - "type": { - "kind": "struct", - "fields": [ + name: "ChainId"; + type: { + kind: "struct"; + fields: [ { - "name": "id", - "type": "u16" + name: "id"; + type: "u16"; } - ] - } + ]; + }; }, { - "name": "Mode", - "type": { - "kind": "enum", - "variants": [ + name: "Mode"; + type: { + kind: "enum"; + variants: [ { - "name": "Locking" + name: "Locking"; }, { - "name": "Burning" + name: "Burning"; } - ] - } + ]; + }; }, { - "name": "TrimmedAmount", - "type": { - "kind": "struct", - "fields": [ + name: "TrimmedAmount"; + type: { + kind: "struct"; + fields: [ { - "name": "amount", - "type": "u64" + name: "amount"; + type: "u64"; }, { - "name": "decimals", - "type": "u8" + name: "decimals"; + type: "u8"; } - ] - } + ]; + }; }, { - "name": "BridgeConfig", - "type": { - "kind": "struct", - "fields": [ + name: "BridgeConfig"; + type: { + kind: "struct"; + fields: [ { - "name": "guardianSetExpirationTime", - "docs": [ + name: "guardianSetExpirationTime"; + docs: [ "Period for how long a guardian set is valid after it has been replaced by a new one. This", "guarantees that VAAs issued by that set can still be submitted for a certain period. In", "this period we still trust the old guardian set." - ], - "type": "u32" + ]; + type: "u32"; }, { - "name": "fee", - "docs": [ + name: "fee"; + docs: [ "Amount of lamports that needs to be paid to the protocol to post a message" - ], - "type": "u64" + ]; + type: "u64"; } - ] - } + ]; + }; } - ], - "errors": [ + ]; + errors: [ { - "code": 6000, - "name": "CantReleaseYet", - "msg": "CantReleaseYet" + code: 6000; + name: "CantReleaseYet"; + msg: "CantReleaseYet"; }, { - "code": 6001, - "name": "InvalidPendingOwner", - "msg": "InvalidPendingOwner" + code: 6001; + name: "InvalidPendingOwner"; + msg: "InvalidPendingOwner"; }, { - "code": 6002, - "name": "InvalidChainId", - "msg": "InvalidChainId" + code: 6002; + name: "InvalidChainId"; + msg: "InvalidChainId"; }, { - "code": 6003, - "name": "InvalidRecipientAddress", - "msg": "InvalidRecipientAddress" + code: 6003; + name: "InvalidRecipientAddress"; + msg: "InvalidRecipientAddress"; }, { - "code": 6004, - "name": "InvalidTransceiverPeer", - "msg": "InvalidTransceiverPeer" + code: 6004; + name: "InvalidTransceiverPeer"; + msg: "InvalidTransceiverPeer"; }, { - "code": 6005, - "name": "InvalidNttManagerPeer", - "msg": "InvalidNttManagerPeer" + code: 6005; + name: "InvalidNttManagerPeer"; + msg: "InvalidNttManagerPeer"; }, { - "code": 6006, - "name": "InvalidRecipientNttManager", - "msg": "InvalidRecipientNttManager" + code: 6006; + name: "InvalidRecipientNttManager"; + msg: "InvalidRecipientNttManager"; }, { - "code": 6007, - "name": "TransferAlreadyRedeemed", - "msg": "TransferAlreadyRedeemed" + code: 6007; + name: "TransferAlreadyRedeemed"; + msg: "TransferAlreadyRedeemed"; }, { - "code": 6008, - "name": "TransferCannotBeRedeemed", - "msg": "TransferCannotBeRedeemed" + code: 6008; + name: "TransferCannotBeRedeemed"; + msg: "TransferCannotBeRedeemed"; }, { - "code": 6009, - "name": "TransferNotApproved", - "msg": "TransferNotApproved" + code: 6009; + name: "TransferNotApproved"; + msg: "TransferNotApproved"; }, { - "code": 6010, - "name": "MessageAlreadySent", - "msg": "MessageAlreadySent" + code: 6010; + name: "MessageAlreadySent"; + msg: "MessageAlreadySent"; }, { - "code": 6011, - "name": "InvalidMode", - "msg": "InvalidMode" + code: 6011; + name: "InvalidMode"; + msg: "InvalidMode"; }, { - "code": 6012, - "name": "InvalidMintAuthority", - "msg": "InvalidMintAuthority" + code: 6012; + name: "InvalidMintAuthority"; + msg: "InvalidMintAuthority"; }, { - "code": 6013, - "name": "TransferExceedsRateLimit", - "msg": "TransferExceedsRateLimit" + code: 6013; + name: "TransferExceedsRateLimit"; + msg: "TransferExceedsRateLimit"; }, { - "code": 6014, - "name": "Paused", - "msg": "Paused" + code: 6014; + name: "Paused"; + msg: "Paused"; }, { - "code": 6015, - "name": "DisabledTransceiver", - "msg": "DisabledTransceiver" + code: 6015; + name: "DisabledTransceiver"; + msg: "DisabledTransceiver"; }, { - "code": 6016, - "name": "InvalidDeployer", - "msg": "InvalidDeployer" + code: 6016; + name: "InvalidDeployer"; + msg: "InvalidDeployer"; }, { - "code": 6017, - "name": "BadAmountAfterTransfer", - "msg": "BadAmountAfterTransfer" + code: 6017; + name: "BadAmountAfterTransfer"; + msg: "BadAmountAfterTransfer"; }, { - "code": 6018, - "name": "BadAmountAfterBurn", - "msg": "BadAmountAfterBurn" + code: 6018; + name: "BadAmountAfterBurn"; + msg: "BadAmountAfterBurn"; }, { - "code": 6019, - "name": "ZeroThreshold", - "msg": "ZeroThreshold" + code: 6019; + name: "ZeroThreshold"; + msg: "ZeroThreshold"; }, { - "code": 6020, - "name": "OverflowExponent", - "msg": "OverflowExponent" + code: 6020; + name: "OverflowExponent"; + msg: "OverflowExponent"; }, { - "code": 6021, - "name": "OverflowScaledAmount", - "msg": "OverflowScaledAmount" + code: 6021; + name: "OverflowScaledAmount"; + msg: "OverflowScaledAmount"; }, { - "code": 6022, - "name": "BitmapIndexOutOfBounds", - "msg": "BitmapIndexOutOfBounds" + code: 6022; + name: "BitmapIndexOutOfBounds"; + msg: "BitmapIndexOutOfBounds"; }, { - "code": 6023, - "name": "NoRegisteredTransceivers", - "msg": "NoRegisteredTransceivers" + code: 6023; + name: "NoRegisteredTransceivers"; + msg: "NoRegisteredTransceivers"; } - ] -} + ]; +}; export const IDL: ExampleNativeTokenTransfers = { - "version": "2.0.0", - "name": "example_native_token_transfers", - "instructions": [ + version: "2.0.0", + name: "example_native_token_transfers", + instructions: [ { - "name": "initialize", - "accounts": [ + name: "initialize", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "deployer", - "isMut": false, - "isSigner": true + name: "deployer", + isMut: false, + isSigner: true, }, { - "name": "programData", - "isMut": false, - "isSigner": false + name: "programData", + isMut: false, + isSigner: false, }, { - "name": "config", - "isMut": true, - "isSigner": false + name: "config", + isMut: true, + isSigner: false, }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint", + isMut: false, + isSigner: false, }, { - "name": "rateLimit", - "isMut": true, - "isSigner": false + name: "rateLimit", + isMut: true, + isSigner: false, }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false, - "docs": [ + name: "tokenAuthority", + isMut: false, + isSigner: false, + docs: [ "In any case, this function is used to set the Config and initialize the program so we", "assume the caller of this function will have total control over the program.", "", - "TODO: Using `UncheckedAccount` here leads to \"Access violation in stack frame ...\".", - "Could refactor code to use `Box<_>` to reduce stack size." - ] + 'TODO: Using `UncheckedAccount` here leads to "Access violation in stack frame ...".', + "Could refactor code to use `Box<_>` to reduce stack size.", + ], }, { - "name": "custody", - "isMut": true, - "isSigner": false, - "docs": [ + name: "custody", + isMut: true, + isSigner: false, + docs: [ "The custody account that holds tokens in locking mode and temporarily", "holds tokens in burning mode.", - "function if the token account has already been created." - ] + "function if the token account has already been created.", + ], }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false, - "docs": [ - "associated token account for the given mint." - ] + name: "tokenProgram", + isMut: false, + isSigner: false, + docs: ["associated token account for the given mint."], }, { - "name": "associatedTokenProgram", - "isMut": false, - "isSigner": false + name: "associatedTokenProgram", + isMut: false, + isSigner: false, }, { - "name": "bpfLoaderUpgradeableProgram", - "isMut": false, - "isSigner": false + name: "bpfLoaderUpgradeableProgram", + isMut: false, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + name: "systemProgram", + isMut: false, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "InitializeArgs" - } - } - ] + name: "args", + type: { + defined: "InitializeArgs", + }, + }, + ], }, { - "name": "initializeLut", - "accounts": [ + name: "initializeLut", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "authority", - "isMut": false, - "isSigner": false + name: "authority", + isMut: false, + isSigner: false, }, { - "name": "lutAddress", - "isMut": true, - "isSigner": false + name: "lutAddress", + isMut: true, + isSigner: false, }, { - "name": "lut", - "isMut": true, - "isSigner": false + name: "lut", + isMut: true, + isSigner: false, }, { - "name": "lutProgram", - "isMut": false, - "isSigner": false + name: "lutProgram", + isMut: false, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram", + isMut: false, + isSigner: false, }, { - "name": "entries", - "accounts": [ + name: "entries", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "custody", - "isMut": false, - "isSigner": false + name: "custody", + isMut: false, + isSigner: false, }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram", + isMut: false, + isSigner: false, }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint", + isMut: false, + isSigner: false, }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false + name: "tokenAuthority", + isMut: false, + isSigner: false, }, { - "name": "outboxRateLimit", - "isMut": false, - "isSigner": false + name: "outboxRateLimit", + isMut: false, + isSigner: false, }, { - "name": "wormhole", - "accounts": [ + name: "wormhole", + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge", + isMut: true, + isSigner: false, }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector", + isMut: true, + isSigner: false, }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence", + isMut: true, + isSigner: false, }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program", + isMut: false, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram", + isMut: false, + isSigner: false, }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock", + isMut: false, + isSigner: false, }, { - "name": "rent", - "isMut": false, - "isSigner": false - } - ] - } - ] - } + name: "rent", + isMut: false, + isSigner: false, + }, + ], + }, + ], + }, ], - "args": [ + args: [ { - "name": "recentSlot", - "type": "u64" - } - ] + name: "recentSlot", + type: "u64", + }, + ], }, { - "name": "version", - "accounts": [], - "args": [], - "returns": "string" + name: "version", + accounts: [], + args: [], + returns: "string", }, { - "name": "transferBurn", - "accounts": [ + name: "transferBurn", + accounts: [ { - "name": "common", - "accounts": [ + name: "common", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "accounts": [ + name: "config", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false - } - ] + name: "config", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint", + isMut: true, + isSigner: false, }, { - "name": "from", - "isMut": true, - "isSigner": false, - "docs": [ - "account can spend these tokens." - ] + name: "from", + isMut: true, + isSigner: false, + docs: ["account can spend these tokens."], }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram", + isMut: false, + isSigner: false, }, { - "name": "outboxItem", - "isMut": true, - "isSigner": true + name: "outboxItem", + isMut: true, + isSigner: true, }, { - "name": "outboxRateLimit", - "isMut": true, - "isSigner": false + name: "outboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "custody", - "isMut": true, - "isSigner": false, - "docs": [ + name: "custody", + isMut: true, + isSigner: false, + docs: [ "Tokens are always transferred to the custody account first regardless of", "the mode.", - "For an explanation, see the note in [`transfer_burn`]." - ] + "For an explanation, see the note in [`transfer_burn`].", + ], }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ] + name: "systemProgram", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer", + isMut: false, + isSigner: false, }, { - "name": "sessionAuthority", - "isMut": false, - "isSigner": false, - "docs": [ - "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." - ] + name: "sessionAuthority", + isMut: false, + isSigner: false, + docs: [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow.", + ], }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false - } + name: "tokenAuthority", + isMut: false, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "TransferArgs" - } - } - ] + name: "args", + type: { + defined: "TransferArgs", + }, + }, + ], }, { - "name": "transferLock", - "accounts": [ + name: "transferLock", + accounts: [ { - "name": "common", - "accounts": [ + name: "common", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "accounts": [ + name: "config", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false - } - ] + name: "config", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint", + isMut: true, + isSigner: false, }, { - "name": "from", - "isMut": true, - "isSigner": false, - "docs": [ - "account can spend these tokens." - ] + name: "from", + isMut: true, + isSigner: false, + docs: ["account can spend these tokens."], }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram", + isMut: false, + isSigner: false, }, { - "name": "outboxItem", - "isMut": true, - "isSigner": true + name: "outboxItem", + isMut: true, + isSigner: true, }, { - "name": "outboxRateLimit", - "isMut": true, - "isSigner": false + name: "outboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "custody", - "isMut": true, - "isSigner": false, - "docs": [ + name: "custody", + isMut: true, + isSigner: false, + docs: [ "Tokens are always transferred to the custody account first regardless of", "the mode.", - "For an explanation, see the note in [`transfer_burn`]." - ] + "For an explanation, see the note in [`transfer_burn`].", + ], }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ] + name: "systemProgram", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer", + isMut: false, + isSigner: false, }, { - "name": "sessionAuthority", - "isMut": false, - "isSigner": false, - "docs": [ - "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." - ] - } + name: "sessionAuthority", + isMut: false, + isSigner: false, + docs: [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow.", + ], + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "TransferArgs" - } - } - ] + name: "args", + type: { + defined: "TransferArgs", + }, + }, + ], }, { - "name": "redeem", - "accounts": [ + name: "redeem", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer", + isMut: false, + isSigner: false, }, { - "name": "transceiverMessage", - "isMut": false, - "isSigner": false + name: "transceiverMessage", + isMut: false, + isSigner: false, + docs: ["`Account` and `owner` constraints are mutually-exclusive"], }, { - "name": "transceiver", - "isMut": false, - "isSigner": false + name: "transceiver", + isMut: false, + isSigner: false, }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint", + isMut: false, + isSigner: false, }, { - "name": "inboxItem", - "isMut": true, - "isSigner": false, - "docs": [ + name: "inboxItem", + isMut: true, + isSigner: false, + docs: [ "NOTE: This account is content-addressed (PDA seeded by the message hash).", "This is because in a multi-transceiver configuration, the different", - "transceivers \"vote\" on messages (by delivering them). By making the inbox", + 'transceivers "vote" on messages (by delivering them). By making the inbox', "items content-addressed, we can ensure that disagreeing votes don't", "interfere with each other.", "On the first call to [`redeem()`], [`InboxItem`] will be allocated and initialized with", "default values.", - "On subsequent calls, we want to modify the `InboxItem` by \"voting\" on it. Therefore the", + 'On subsequent calls, we want to modify the `InboxItem` by "voting" on it. Therefore the', "program should not fail which would occur when using the `init` constraint.", "The [`InboxItem::init`] field is used to guard against malicious or accidental modification", - "InboxItem fields that should remain constant." - ] + "InboxItem fields that should remain constant.", + ], }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "outboxRateLimit", - "isMut": true, - "isSigner": false + name: "outboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + name: "systemProgram", + isMut: false, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "RedeemArgs" - } - } - ] + name: "args", + type: { + defined: "RedeemArgs", + }, + }, + ], }, { - "name": "releaseInboundMint", - "accounts": [ + name: "releaseInboundMint", + accounts: [ { - "name": "common", - "accounts": [ + name: "common", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "accounts": [ + name: "config", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false - } - ] + name: "config", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "inboxItem", - "isMut": true, - "isSigner": false + name: "inboxItem", + isMut: true, + isSigner: false, }, { - "name": "recipient", - "isMut": true, - "isSigner": false + name: "recipient", + isMut: true, + isSigner: false, }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false, - "docs": [ - "CHECK The seeds constraint ensures that this is the correct address" - ] + name: "tokenAuthority", + isMut: false, + isSigner: false, + docs: [ + "CHECK The seeds constraint ensures that this is the correct address", + ], }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint", + isMut: true, + isSigner: false, }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram", + isMut: false, + isSigner: false, }, { - "name": "custody", - "isMut": true, - "isSigner": false - } - ] - } + name: "custody", + isMut: true, + isSigner: false, + }, + ], + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "ReleaseInboundArgs" - } - } - ] + name: "args", + type: { + defined: "ReleaseInboundArgs", + }, + }, + ], }, { - "name": "releaseInboundUnlock", - "accounts": [ + name: "releaseInboundUnlock", + accounts: [ { - "name": "common", - "accounts": [ + name: "common", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "accounts": [ + name: "config", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false - } - ] + name: "config", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "inboxItem", - "isMut": true, - "isSigner": false + name: "inboxItem", + isMut: true, + isSigner: false, }, { - "name": "recipient", - "isMut": true, - "isSigner": false + name: "recipient", + isMut: true, + isSigner: false, }, { - "name": "tokenAuthority", - "isMut": false, - "isSigner": false, - "docs": [ - "CHECK The seeds constraint ensures that this is the correct address" - ] + name: "tokenAuthority", + isMut: false, + isSigner: false, + docs: [ + "CHECK The seeds constraint ensures that this is the correct address", + ], }, { - "name": "mint", - "isMut": true, - "isSigner": false + name: "mint", + isMut: true, + isSigner: false, }, { - "name": "tokenProgram", - "isMut": false, - "isSigner": false + name: "tokenProgram", + isMut: false, + isSigner: false, }, { - "name": "custody", - "isMut": true, - "isSigner": false - } - ] - } + name: "custody", + isMut: true, + isSigner: false, + }, + ], + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "ReleaseInboundArgs" - } - } - ] + name: "args", + type: { + defined: "ReleaseInboundArgs", + }, + }, + ], }, { - "name": "transferOwnership", - "accounts": [ + name: "transferOwnership", + accounts: [ { - "name": "config", - "isMut": true, - "isSigner": false + name: "config", + isMut: true, + isSigner: false, }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "newOwner", - "isMut": false, - "isSigner": false + name: "newOwner", + isMut: false, + isSigner: false, }, { - "name": "upgradeLock", - "isMut": false, - "isSigner": false + name: "upgradeLock", + isMut: false, + isSigner: false, }, { - "name": "programData", - "isMut": true, - "isSigner": false + name: "programData", + isMut: true, + isSigner: false, }, { - "name": "bpfLoaderUpgradeableProgram", - "isMut": false, - "isSigner": false - } + name: "bpfLoaderUpgradeableProgram", + isMut: false, + isSigner: false, + }, ], - "args": [] + args: [], }, { - "name": "claimOwnership", - "accounts": [ + name: "claimOwnership", + accounts: [ { - "name": "config", - "isMut": true, - "isSigner": false + name: "config", + isMut: true, + isSigner: false, }, { - "name": "upgradeLock", - "isMut": false, - "isSigner": false + name: "upgradeLock", + isMut: false, + isSigner: false, }, { - "name": "newOwner", - "isMut": false, - "isSigner": true + name: "newOwner", + isMut: false, + isSigner: true, }, { - "name": "programData", - "isMut": true, - "isSigner": false + name: "programData", + isMut: true, + isSigner: false, }, { - "name": "bpfLoaderUpgradeableProgram", - "isMut": false, - "isSigner": false - } + name: "bpfLoaderUpgradeableProgram", + isMut: false, + isSigner: false, + }, ], - "args": [] + args: [], }, { - "name": "setPaused", - "accounts": [ + name: "setPaused", + accounts: [ { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "config", - "isMut": true, - "isSigner": false - } + name: "config", + isMut: true, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "pause", - "type": "bool" - } - ] + name: "pause", + type: "bool", + }, + ], }, { - "name": "setPeer", - "accounts": [ + name: "setPeer", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "peer", - "isMut": true, - "isSigner": false + name: "peer", + isMut: true, + isSigner: false, }, { - "name": "inboxRateLimit", - "isMut": true, - "isSigner": false + name: "inboxRateLimit", + isMut: true, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + name: "systemProgram", + isMut: false, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "SetPeerArgs" - } - } - ] + name: "args", + type: { + defined: "SetPeerArgs", + }, + }, + ], }, { - "name": "registerTransceiver", - "accounts": [ + name: "registerTransceiver", + accounts: [ { - "name": "config", - "isMut": true, - "isSigner": false + name: "config", + isMut: true, + isSigner: false, }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "transceiver", - "isMut": false, - "isSigner": false, - "docs": [ - "used here that wraps the Transceiver account type." - ] + name: "transceiver", + isMut: false, + isSigner: false, + docs: ["used here that wraps the Transceiver account type."], }, { - "name": "registeredTransceiver", - "isMut": true, - "isSigner": false + name: "registeredTransceiver", + isMut: true, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + name: "systemProgram", + isMut: false, + isSigner: false, + }, ], - "args": [] + args: [], }, { - "name": "setOutboundLimit", - "accounts": [ + name: "setOutboundLimit", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "rateLimit", - "isMut": true, - "isSigner": false - } + name: "rateLimit", + isMut: true, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "SetOutboundLimitArgs" - } - } - ] + name: "args", + type: { + defined: "SetOutboundLimitArgs", + }, + }, + ], }, { - "name": "setInboundLimit", - "accounts": [ + name: "setInboundLimit", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "rateLimit", - "isMut": true, - "isSigner": false - } + name: "rateLimit", + isMut: true, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "SetInboundLimitArgs" - } - } - ] + name: "args", + type: { + defined: "SetInboundLimitArgs", + }, + }, + ], }, { - "name": "setWormholePeer", - "accounts": [ + name: "setWormholePeer", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "owner", - "isMut": false, - "isSigner": true + name: "owner", + isMut: false, + isSigner: true, }, { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "peer", - "isMut": true, - "isSigner": false + name: "peer", + isMut: true, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + name: "systemProgram", + isMut: false, + isSigner: false, + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "SetTransceiverPeerArgs" - } - } - ] + name: "args", + type: { + defined: "SetTransceiverPeerArgs", + }, + }, + ], }, { - "name": "receiveWormholeMessage", - "accounts": [ + name: "receiveWormholeMessage", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "accounts": [ + name: "config", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false - } - ] + name: "config", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer", + isMut: false, + isSigner: false, }, { - "name": "vaa", - "isMut": false, - "isSigner": false + name: "vaa", + isMut: false, + isSigner: false, }, { - "name": "transceiverMessage", - "isMut": true, - "isSigner": false + name: "transceiverMessage", + isMut: true, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + name: "systemProgram", + isMut: false, + isSigner: false, + }, ], - "args": [] + args: [], }, { - "name": "releaseWormholeOutbound", - "accounts": [ + name: "releaseWormholeOutbound", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "accounts": [ + name: "config", + accounts: [ { - "name": "config", - "isMut": false, - "isSigner": false - } - ] + name: "config", + isMut: false, + isSigner: false, + }, + ], }, { - "name": "outboxItem", - "isMut": true, - "isSigner": false + name: "outboxItem", + isMut: true, + isSigner: false, }, { - "name": "transceiver", - "isMut": false, - "isSigner": false + name: "transceiver", + isMut: false, + isSigner: false, }, { - "name": "wormholeMessage", - "isMut": true, - "isSigner": false + name: "wormholeMessage", + isMut: true, + isSigner: false, }, { - "name": "emitter", - "isMut": false, - "isSigner": false + name: "emitter", + isMut: false, + isSigner: false, }, { - "name": "wormhole", - "accounts": [ + name: "wormhole", + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge", + isMut: true, + isSigner: false, }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector", + isMut: true, + isSigner: false, }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence", + isMut: true, + isSigner: false, }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program", + isMut: false, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram", + isMut: false, + isSigner: false, }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock", + isMut: false, + isSigner: false, }, { - "name": "rent", - "isMut": false, - "isSigner": false - } - ] - } + name: "rent", + isMut: false, + isSigner: false, + }, + ], + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "ReleaseOutboundArgs" - } - } - ] + name: "args", + type: { + defined: "ReleaseOutboundArgs", + }, + }, + ], }, { - "name": "broadcastWormholeId", - "accounts": [ + name: "broadcastWormholeId", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "mint", - "isMut": false, - "isSigner": false + name: "mint", + isMut: false, + isSigner: false, }, { - "name": "wormholeMessage", - "isMut": true, - "isSigner": true + name: "wormholeMessage", + isMut: true, + isSigner: true, }, { - "name": "emitter", - "isMut": false, - "isSigner": false + name: "emitter", + isMut: false, + isSigner: false, }, { - "name": "wormhole", - "accounts": [ + name: "wormhole", + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge", + isMut: true, + isSigner: false, }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector", + isMut: true, + isSigner: false, }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence", + isMut: true, + isSigner: false, }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program", + isMut: false, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram", + isMut: false, + isSigner: false, }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock", + isMut: false, + isSigner: false, }, { - "name": "rent", - "isMut": false, - "isSigner": false - } - ] - } + name: "rent", + isMut: false, + isSigner: false, + }, + ], + }, ], - "args": [] + args: [], }, { - "name": "broadcastWormholePeer", - "accounts": [ + name: "broadcastWormholePeer", + accounts: [ { - "name": "payer", - "isMut": true, - "isSigner": true + name: "payer", + isMut: true, + isSigner: true, }, { - "name": "config", - "isMut": false, - "isSigner": false + name: "config", + isMut: false, + isSigner: false, }, { - "name": "peer", - "isMut": false, - "isSigner": false + name: "peer", + isMut: false, + isSigner: false, }, { - "name": "wormholeMessage", - "isMut": true, - "isSigner": true + name: "wormholeMessage", + isMut: true, + isSigner: true, }, { - "name": "emitter", - "isMut": false, - "isSigner": false + name: "emitter", + isMut: false, + isSigner: false, }, { - "name": "wormhole", - "accounts": [ + name: "wormhole", + accounts: [ { - "name": "bridge", - "isMut": true, - "isSigner": false + name: "bridge", + isMut: true, + isSigner: false, }, { - "name": "feeCollector", - "isMut": true, - "isSigner": false + name: "feeCollector", + isMut: true, + isSigner: false, }, { - "name": "sequence", - "isMut": true, - "isSigner": false + name: "sequence", + isMut: true, + isSigner: false, }, { - "name": "program", - "isMut": false, - "isSigner": false + name: "program", + isMut: false, + isSigner: false, }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + name: "systemProgram", + isMut: false, + isSigner: false, }, { - "name": "clock", - "isMut": false, - "isSigner": false + name: "clock", + isMut: false, + isSigner: false, }, { - "name": "rent", - "isMut": false, - "isSigner": false - } - ] - } + name: "rent", + isMut: false, + isSigner: false, + }, + ], + }, ], - "args": [ + args: [ { - "name": "args", - "type": { - "defined": "BroadcastPeerArgs" - } - } - ] - } + name: "args", + type: { + defined: "BroadcastPeerArgs", + }, + }, + ], + }, ], - "accounts": [ + accounts: [ { - "name": "config", - "type": { - "kind": "struct", - "fields": [ + name: "config", + type: { + kind: "struct", + fields: [ { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "owner", - "docs": [ - "Owner of the program." - ], - "type": "publicKey" + name: "owner", + docs: ["Owner of the program."], + type: "publicKey", }, { - "name": "pendingOwner", - "docs": [ - "Pending next owner (before claiming ownership)." - ], - "type": { - "option": "publicKey" - } + name: "pendingOwner", + docs: ["Pending next owner (before claiming ownership)."], + type: { + option: "publicKey", + }, }, { - "name": "mint", - "docs": [ - "Mint address of the token managed by this program." - ], - "type": "publicKey" + name: "mint", + docs: ["Mint address of the token managed by this program."], + type: "publicKey", }, { - "name": "tokenProgram", - "docs": [ + name: "tokenProgram", + docs: [ "Address of the token program (token or token22). This could always be queried", "from the [`mint`] account's owner, but storing it here avoids an indirection", - "on the client side." + "on the client side.", ], - "type": "publicKey" + type: "publicKey", }, { - "name": "mode", - "docs": [ + name: "mode", + docs: [ "The mode that this program is running in. This is used to determine", - "whether the program is burning tokens or locking tokens." + "whether the program is burning tokens or locking tokens.", ], - "type": { - "defined": "Mode" - } + type: { + defined: "Mode", + }, }, { - "name": "chainId", - "docs": [ + name: "chainId", + docs: [ "The chain id of the chain that this program is running on. We don't", "hardcode this so that the program is deployable on any potential SVM", - "forks." + "forks.", ], - "type": { - "defined": "ChainId" - } + type: { + defined: "ChainId", + }, }, { - "name": "nextTransceiverId", - "docs": [ - "The next transceiver id to use when registering an transceiver." + name: "nextTransceiverId", + docs: [ + "The next transceiver id to use when registering an transceiver.", ], - "type": "u8" + type: "u8", }, { - "name": "threshold", - "docs": [ + name: "threshold", + docs: [ "The number of transceivers that must attest to a transfer before it is", - "accepted." + "accepted.", ], - "type": "u8" + type: "u8", }, { - "name": "enabledTransceivers", - "docs": [ + name: "enabledTransceivers", + docs: [ "Bitmap of enabled transceivers.", - "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + "The maximum number of transceivers is equal to [`Bitmap::BITS`].", ], - "type": { - "defined": "Bitmap" - } + type: { + defined: "Bitmap", + }, }, { - "name": "paused", - "docs": [ - "Pause the program. This is useful for upgrades and other maintenance." + name: "paused", + docs: [ + "Pause the program. This is useful for upgrades and other maintenance.", ], - "type": "bool" + type: "bool", }, { - "name": "custody", - "docs": [ - "The custody account that holds tokens in locking mode." - ], - "type": "publicKey" - } - ] - } + name: "custody", + docs: ["The custody account that holds tokens in locking mode."], + type: "publicKey", + }, + ], + }, }, { - "name": "LUT", - "type": { - "kind": "struct", - "fields": [ + name: "LUT", + type: { + kind: "struct", + fields: [ { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "address", - "type": "publicKey" - } - ] - } + name: "address", + type: "publicKey", + }, + ], + }, }, { - "name": "nttManagerPeer", - "docs": [ - "A peer on another chain. Stored in a PDA seeded by the chain id." + name: "nttManagerPeer", + docs: [ + "A peer on another chain. Stored in a PDA seeded by the chain id.", ], - "type": { - "kind": "struct", - "fields": [ + type: { + kind: "struct", + fields: [ { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "address", + type: { + array: ["u8", 32], + }, }, { - "name": "tokenDecimals", - "type": "u8" - } - ] - } + name: "tokenDecimals", + type: "u8", + }, + ], + }, }, { - "name": "inboxItem", - "type": { - "kind": "struct", - "fields": [ + name: "inboxItem", + type: { + kind: "struct", + fields: [ { - "name": "init", - "type": "bool" + name: "init", + type: "bool", }, { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "amount", - "type": "u64" + name: "amount", + type: "u64", }, { - "name": "recipientAddress", - "type": "publicKey" + name: "recipientAddress", + type: "publicKey", }, { - "name": "votes", - "type": { - "defined": "Bitmap" - } + name: "votes", + type: { + defined: "Bitmap", + }, }, { - "name": "releaseStatus", - "type": { - "defined": "ReleaseStatus" - } - } - ] - } + name: "releaseStatus", + type: { + defined: "ReleaseStatus", + }, + }, + ], + }, }, { - "name": "inboxRateLimit", - "docs": [ + name: "inboxRateLimit", + docs: [ "Inbound rate limit per chain.", - "SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.)" + "SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.)", ], - "type": { - "kind": "struct", - "fields": [ + type: { + kind: "struct", + fields: [ { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "rateLimit", - "type": { - "defined": "RateLimitState" - } - } - ] - } + name: "rateLimit", + type: { + defined: "RateLimitState", + }, + }, + ], + }, }, { - "name": "outboxItem", - "type": { - "kind": "struct", - "fields": [ + name: "outboxItem", + type: { + kind: "struct", + fields: [ { - "name": "amount", - "type": { - "defined": "TrimmedAmount" - } + name: "amount", + type: { + defined: "TrimmedAmount", + }, }, { - "name": "sender", - "type": "publicKey" + name: "sender", + type: "publicKey", }, { - "name": "recipientChain", - "type": { - "defined": "ChainId" - } + name: "recipientChain", + type: { + defined: "ChainId", + }, }, { - "name": "recipientNttManager", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "recipientNttManager", + type: { + array: ["u8", 32], + }, }, { - "name": "recipientAddress", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "recipientAddress", + type: { + array: ["u8", 32], + }, }, { - "name": "releaseTimestamp", - "type": "i64" + name: "releaseTimestamp", + type: "i64", }, { - "name": "released", - "type": { - "defined": "Bitmap" - } - } - ] - } + name: "released", + type: { + defined: "Bitmap", + }, + }, + ], + }, }, { - "name": "outboxRateLimit", - "type": { - "kind": "struct", - "fields": [ + name: "outboxRateLimit", + type: { + kind: "struct", + fields: [ { - "name": "rateLimit", - "type": { - "defined": "RateLimitState" - } - } - ] - } + name: "rateLimit", + type: { + defined: "RateLimitState", + }, + }, + ], + }, }, { - "name": "registeredTransceiver", - "type": { - "kind": "struct", - "fields": [ + name: "registeredTransceiver", + type: { + kind: "struct", + fields: [ { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "id", - "type": "u8" + name: "id", + type: "u8", }, { - "name": "transceiverAddress", - "type": "publicKey" - } - ] - } + name: "transceiverAddress", + type: "publicKey", + }, + ], + }, }, { - "name": "transceiverPeer", - "docs": [ - "A peer on another chain. Stored in a PDA seeded by the chain id." + name: "transceiverPeer", + docs: [ + "A peer on another chain. Stored in a PDA seeded by the chain id.", ], - "type": { - "kind": "struct", - "fields": [ + type: { + kind: "struct", + fields: [ { - "name": "bump", - "type": "u8" + name: "bump", + type: "u8", }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } - } - ] - } + name: "address", + type: { + array: ["u8", 32], + }, + }, + ], + }, }, { - "name": "bridgeData", - "type": { - "kind": "struct", - "fields": [ + name: "bridgeData", + type: { + kind: "struct", + fields: [ { - "name": "guardianSetIndex", - "docs": [ - "The current guardian set index, used to decide which signature sets to accept." + name: "guardianSetIndex", + docs: [ + "The current guardian set index, used to decide which signature sets to accept.", ], - "type": "u32" + type: "u32", }, { - "name": "lastLamports", - "docs": [ - "Lamports in the collection account" - ], - "type": "u64" + name: "lastLamports", + docs: ["Lamports in the collection account"], + type: "u64", }, { - "name": "config", - "docs": [ - "Bridge configuration, which is set once upon initialization." + name: "config", + docs: [ + "Bridge configuration, which is set once upon initialization.", ], - "type": { - "defined": "BridgeConfig" - } - } - ] - } - } + type: { + defined: "BridgeConfig", + }, + }, + ], + }, + }, ], - "types": [ + types: [ { - "name": "Bitmap", - "type": { - "kind": "struct", - "fields": [ + name: "Bitmap", + type: { + kind: "struct", + fields: [ { - "name": "map", - "type": "u128" - } - ] - } + name: "map", + type: "u128", + }, + ], + }, }, { - "name": "SetInboundLimitArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetInboundLimitArgs", + type: { + kind: "struct", + fields: [ { - "name": "limit", - "type": "u64" + name: "limit", + type: "u64", }, { - "name": "chainId", - "type": { - "defined": "ChainId" - } - } - ] - } + name: "chainId", + type: { + defined: "ChainId", + }, + }, + ], + }, }, { - "name": "SetOutboundLimitArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetOutboundLimitArgs", + type: { + kind: "struct", + fields: [ { - "name": "limit", - "type": "u64" - } - ] - } + name: "limit", + type: "u64", + }, + ], + }, }, { - "name": "SetPeerArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetPeerArgs", + type: { + kind: "struct", + fields: [ { - "name": "chainId", - "type": { - "defined": "ChainId" - } + name: "chainId", + type: { + defined: "ChainId", + }, }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "address", + type: { + array: ["u8", 32], + }, }, { - "name": "limit", - "type": "u64" + name: "limit", + type: "u64", }, { - "name": "tokenDecimals", - "docs": [ - "The token decimals on the peer chain." - ], - "type": "u8" - } - ] - } + name: "tokenDecimals", + docs: ["The token decimals on the peer chain."], + type: "u8", + }, + ], + }, }, { - "name": "InitializeArgs", - "type": { - "kind": "struct", - "fields": [ + name: "InitializeArgs", + type: { + kind: "struct", + fields: [ { - "name": "chainId", - "type": "u16" + name: "chainId", + type: "u16", }, { - "name": "limit", - "type": "u64" + name: "limit", + type: "u64", }, { - "name": "mode", - "type": { - "defined": "Mode" - } - } - ] - } + name: "mode", + type: { + defined: "Mode", + }, + }, + ], + }, }, { - "name": "RedeemArgs", - "type": { - "kind": "struct", - "fields": [] - } + name: "RedeemArgs", + type: { + kind: "struct", + fields: [], + }, }, { - "name": "ReleaseInboundArgs", - "type": { - "kind": "struct", - "fields": [ + name: "ReleaseInboundArgs", + type: { + kind: "struct", + fields: [ { - "name": "revertOnDelay", - "type": "bool" - } - ] - } + name: "revertOnDelay", + type: "bool", + }, + ], + }, }, { - "name": "TransferArgs", - "type": { - "kind": "struct", - "fields": [ + name: "TransferArgs", + type: { + kind: "struct", + fields: [ { - "name": "amount", - "type": "u64" + name: "amount", + type: "u64", }, { - "name": "recipientChain", - "type": { - "defined": "ChainId" - } + name: "recipientChain", + type: { + defined: "ChainId", + }, }, { - "name": "recipientAddress", - "type": { - "array": [ - "u8", - 32 - ] - } + name: "recipientAddress", + type: { + array: ["u8", 32], + }, }, { - "name": "shouldQueue", - "type": "bool" - } - ] - } + name: "shouldQueue", + type: "bool", + }, + ], + }, }, { - "name": "ReleaseStatus", - "docs": [ + name: "ReleaseStatus", + docs: [ "The status of an InboxItem. This determines whether the tokens are minted/unlocked to the recipient. As", "such, this must be used as a state machine that moves forward in a linear manner. A state", - "should never \"move backward\" to a previous state (e.g. should never move from `Released` to", - "`ReleaseAfter`)." + 'should never "move backward" to a previous state (e.g. should never move from `Released` to', + "`ReleaseAfter`).", ], - "type": { - "kind": "enum", - "variants": [ + type: { + kind: "enum", + variants: [ { - "name": "NotApproved" + name: "NotApproved", }, { - "name": "ReleaseAfter", - "fields": [ - "i64" - ] + name: "ReleaseAfter", + fields: ["i64"], }, { - "name": "Released" - } - ] - } + name: "Released", + }, + ], + }, }, { - "name": "RateLimitState", - "type": { - "kind": "struct", - "fields": [ + name: "RateLimitState", + type: { + kind: "struct", + fields: [ { - "name": "limit", - "docs": [ - "The maximum capacity of the rate limiter." - ], - "type": "u64" + name: "limit", + docs: ["The maximum capacity of the rate limiter."], + type: "u64", }, { - "name": "capacityAtLastTx", - "docs": [ + name: "capacityAtLastTx", + docs: [ "The capacity of the rate limiter at `last_tx_timestamp`.", "The actual current capacity is calculated in `capacity_at`, by", "accounting for the time that has passed since `last_tx_timestamp` and", - "the refill rate." + "the refill rate.", ], - "type": "u64" + type: "u64", }, { - "name": "lastTxTimestamp", - "docs": [ + name: "lastTxTimestamp", + docs: [ "The timestamp of the last transaction that counted towards the current", "capacity. Transactions that exceeded the capacity do not count, they are", - "just delayed." + "just delayed.", ], - "type": "i64" - } - ] - } + type: "i64", + }, + ], + }, }, { - "name": "SetTransceiverPeerArgs", - "type": { - "kind": "struct", - "fields": [ + name: "SetTransceiverPeerArgs", + type: { + kind: "struct", + fields: [ { - "name": "chainId", - "type": { - "defined": "ChainId" - } + name: "chainId", + type: { + defined: "ChainId", + }, }, { - "name": "address", - "type": { - "array": [ - "u8", - 32 - ] - } - } - ] - } + name: "address", + type: { + array: ["u8", 32], + }, + }, + ], + }, }, { - "name": "BroadcastPeerArgs", - "type": { - "kind": "struct", - "fields": [ + name: "BroadcastPeerArgs", + type: { + kind: "struct", + fields: [ { - "name": "chainId", - "type": "u16" - } - ] - } + name: "chainId", + type: "u16", + }, + ], + }, }, { - "name": "ReleaseOutboundArgs", - "type": { - "kind": "struct", - "fields": [ + name: "ReleaseOutboundArgs", + type: { + kind: "struct", + fields: [ { - "name": "revertOnDelay", - "type": "bool" - } - ] - } + name: "revertOnDelay", + type: "bool", + }, + ], + }, }, { - "name": "ChainId", - "type": { - "kind": "struct", - "fields": [ + name: "ChainId", + type: { + kind: "struct", + fields: [ { - "name": "id", - "type": "u16" - } - ] - } + name: "id", + type: "u16", + }, + ], + }, }, { - "name": "Mode", - "type": { - "kind": "enum", - "variants": [ + name: "Mode", + type: { + kind: "enum", + variants: [ { - "name": "Locking" + name: "Locking", }, { - "name": "Burning" - } - ] - } + name: "Burning", + }, + ], + }, }, { - "name": "TrimmedAmount", - "type": { - "kind": "struct", - "fields": [ + name: "TrimmedAmount", + type: { + kind: "struct", + fields: [ { - "name": "amount", - "type": "u64" + name: "amount", + type: "u64", }, { - "name": "decimals", - "type": "u8" - } - ] - } + name: "decimals", + type: "u8", + }, + ], + }, }, { - "name": "BridgeConfig", - "type": { - "kind": "struct", - "fields": [ + name: "BridgeConfig", + type: { + kind: "struct", + fields: [ { - "name": "guardianSetExpirationTime", - "docs": [ + name: "guardianSetExpirationTime", + docs: [ "Period for how long a guardian set is valid after it has been replaced by a new one. This", "guarantees that VAAs issued by that set can still be submitted for a certain period. In", - "this period we still trust the old guardian set." + "this period we still trust the old guardian set.", ], - "type": "u32" + type: "u32", }, { - "name": "fee", - "docs": [ - "Amount of lamports that needs to be paid to the protocol to post a message" + name: "fee", + docs: [ + "Amount of lamports that needs to be paid to the protocol to post a message", ], - "type": "u64" - } - ] - } - } + type: "u64", + }, + ], + }, + }, ], - "errors": [ + errors: [ { - "code": 6000, - "name": "CantReleaseYet", - "msg": "CantReleaseYet" + code: 6000, + name: "CantReleaseYet", + msg: "CantReleaseYet", }, { - "code": 6001, - "name": "InvalidPendingOwner", - "msg": "InvalidPendingOwner" + code: 6001, + name: "InvalidPendingOwner", + msg: "InvalidPendingOwner", }, { - "code": 6002, - "name": "InvalidChainId", - "msg": "InvalidChainId" + code: 6002, + name: "InvalidChainId", + msg: "InvalidChainId", }, { - "code": 6003, - "name": "InvalidRecipientAddress", - "msg": "InvalidRecipientAddress" + code: 6003, + name: "InvalidRecipientAddress", + msg: "InvalidRecipientAddress", }, { - "code": 6004, - "name": "InvalidTransceiverPeer", - "msg": "InvalidTransceiverPeer" + code: 6004, + name: "InvalidTransceiverPeer", + msg: "InvalidTransceiverPeer", }, { - "code": 6005, - "name": "InvalidNttManagerPeer", - "msg": "InvalidNttManagerPeer" + code: 6005, + name: "InvalidNttManagerPeer", + msg: "InvalidNttManagerPeer", }, { - "code": 6006, - "name": "InvalidRecipientNttManager", - "msg": "InvalidRecipientNttManager" + code: 6006, + name: "InvalidRecipientNttManager", + msg: "InvalidRecipientNttManager", }, { - "code": 6007, - "name": "TransferAlreadyRedeemed", - "msg": "TransferAlreadyRedeemed" + code: 6007, + name: "TransferAlreadyRedeemed", + msg: "TransferAlreadyRedeemed", }, { - "code": 6008, - "name": "TransferCannotBeRedeemed", - "msg": "TransferCannotBeRedeemed" + code: 6008, + name: "TransferCannotBeRedeemed", + msg: "TransferCannotBeRedeemed", }, { - "code": 6009, - "name": "TransferNotApproved", - "msg": "TransferNotApproved" + code: 6009, + name: "TransferNotApproved", + msg: "TransferNotApproved", }, { - "code": 6010, - "name": "MessageAlreadySent", - "msg": "MessageAlreadySent" + code: 6010, + name: "MessageAlreadySent", + msg: "MessageAlreadySent", }, { - "code": 6011, - "name": "InvalidMode", - "msg": "InvalidMode" + code: 6011, + name: "InvalidMode", + msg: "InvalidMode", }, { - "code": 6012, - "name": "InvalidMintAuthority", - "msg": "InvalidMintAuthority" + code: 6012, + name: "InvalidMintAuthority", + msg: "InvalidMintAuthority", }, { - "code": 6013, - "name": "TransferExceedsRateLimit", - "msg": "TransferExceedsRateLimit" + code: 6013, + name: "TransferExceedsRateLimit", + msg: "TransferExceedsRateLimit", }, { - "code": 6014, - "name": "Paused", - "msg": "Paused" + code: 6014, + name: "Paused", + msg: "Paused", }, { - "code": 6015, - "name": "DisabledTransceiver", - "msg": "DisabledTransceiver" + code: 6015, + name: "DisabledTransceiver", + msg: "DisabledTransceiver", }, { - "code": 6016, - "name": "InvalidDeployer", - "msg": "InvalidDeployer" + code: 6016, + name: "InvalidDeployer", + msg: "InvalidDeployer", }, { - "code": 6017, - "name": "BadAmountAfterTransfer", - "msg": "BadAmountAfterTransfer" + code: 6017, + name: "BadAmountAfterTransfer", + msg: "BadAmountAfterTransfer", }, { - "code": 6018, - "name": "BadAmountAfterBurn", - "msg": "BadAmountAfterBurn" + code: 6018, + name: "BadAmountAfterBurn", + msg: "BadAmountAfterBurn", }, { - "code": 6019, - "name": "ZeroThreshold", - "msg": "ZeroThreshold" + code: 6019, + name: "ZeroThreshold", + msg: "ZeroThreshold", }, { - "code": 6020, - "name": "OverflowExponent", - "msg": "OverflowExponent" + code: 6020, + name: "OverflowExponent", + msg: "OverflowExponent", }, { - "code": 6021, - "name": "OverflowScaledAmount", - "msg": "OverflowScaledAmount" + code: 6021, + name: "OverflowScaledAmount", + msg: "OverflowScaledAmount", }, { - "code": 6022, - "name": "BitmapIndexOutOfBounds", - "msg": "BitmapIndexOutOfBounds" + code: 6022, + name: "BitmapIndexOutOfBounds", + msg: "BitmapIndexOutOfBounds", }, { - "code": 6023, - "name": "NoRegisteredTransceivers", - "msg": "NoRegisteredTransceivers" - } - ] -} - + code: 6023, + name: "NoRegisteredTransceivers", + msg: "NoRegisteredTransceivers", + }, + ], +}; diff --git a/solana/ts/idl/3_0_0/json/dummy_transfer_hook.json b/solana/ts/idl/3_0_0/json/dummy_transfer_hook.json new file mode 100644 index 000000000..21ade4d20 --- /dev/null +++ b/solana/ts/idl/3_0_0/json/dummy_transfer_hook.json @@ -0,0 +1,110 @@ +{ + "version": "3.0.0", + "name": "dummy_transfer_hook", + "instructions": [ + { + "name": "initializeExtraAccountMetaList", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "extraAccountMetaList", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "counter", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferHook", + "accounts": [ + { + "name": "sourceToken", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "destinationToken", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "extraAccountMetaList", + "isMut": false, + "isSigner": false + }, + { + "name": "dummyAccount", + "isMut": false, + "isSigner": false, + "docs": [ + "computes and the on-chain code correctly passes on the PDA." + ] + }, + { + "name": "counter", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "Counter", + "type": { + "kind": "struct", + "fields": [ + { + "name": "count", + "type": "u64" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/solana/ts/idl/3_0_0/json/example_native_token_transfers.json b/solana/ts/idl/3_0_0/json/example_native_token_transfers.json new file mode 100644 index 000000000..cdc046fa1 --- /dev/null +++ b/solana/ts/idl/3_0_0/json/example_native_token_transfers.json @@ -0,0 +1,2024 @@ +{ + "version": "3.0.0", + "name": "example_native_token_transfers", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "deployer", + "isMut": false, + "isSigner": true + }, + { + "name": "programData", + "isMut": false, + "isSigner": false + }, + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "In any case, this function is used to set the Config and initialize the program so we", + "assume the caller of this function will have total control over the program.", + "", + "TODO: Using `UncheckedAccount` here leads to \"Access violation in stack frame ...\".", + "Could refactor code to use `Box<_>` to reduce stack size." + ] + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "The custody account that holds tokens in locking mode and temporarily", + "holds tokens in burning mode.", + "function if the token account has already been created." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "associated token account for the given mint." + ] + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "InitializeArgs" + } + } + ] + }, + { + "name": "initializeLut", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "lutAddress", + "isMut": true, + "isSigner": false + }, + { + "name": "lut", + "isMut": true, + "isSigner": false + }, + { + "name": "lutProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "entries", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxRateLimit", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ] + } + ], + "args": [ + { + "name": "recentSlot", + "type": "u64" + } + ] + }, + { + "name": "version", + "accounts": [], + "args": [], + "returns": "string" + }, + { + "name": "transferBurn", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false, + "docs": [ + "account can spend these tokens." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": true + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "Tokens are always transferred to the custody account first regardless of", + "the mode.", + "For an explanation, see the note in [`transfer_burn`]." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "sessionAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." + ] + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "TransferArgs" + } + } + ] + }, + { + "name": "transferLock", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false, + "docs": [ + "account can spend these tokens." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": true + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "Tokens are always transferred to the custody account first regardless of", + "the mode.", + "For an explanation, see the note in [`transfer_burn`]." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "sessionAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "TransferArgs" + } + } + ] + }, + { + "name": "redeem", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": false, + "isSigner": false, + "docs": [ + "`Account` and `owner` constraints are mutually-exclusive" + ] + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false, + "docs": [ + "NOTE: This account is content-addressed (PDA seeded by the message hash).", + "This is because in a multi-transceiver configuration, the different", + "transceivers \"vote\" on messages (by delivering them). By making the inbox", + "items content-addressed, we can ensure that disagreeing votes don't", + "interfere with each other.", + "On the first call to [`redeem()`], [`InboxItem`] will be allocated and initialized with", + "default values.", + "On subsequent calls, we want to modify the `InboxItem` by \"voting\" on it. Therefore the", + "program should not fail which would occur when using the `init` constraint.", + "The [`InboxItem::init`] field is used to guard against malicious or accidental modification", + "InboxItem fields that should remain constant." + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RedeemArgs" + } + } + ] + }, + { + "name": "releaseInboundMint", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "CHECK The seeds constraint ensures that this is the correct address" + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseInboundArgs" + } + } + ] + }, + { + "name": "releaseInboundUnlock", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "CHECK The seeds constraint ensures that this is the correct address" + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseInboundArgs" + } + } + ] + }, + { + "name": "transferOwnership", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferOwnershipOneStepUnchecked", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "claimOwnership", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": true + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setPaused", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pause", + "type": "bool" + } + ] + }, + { + "name": "setPeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetPeerArgs" + } + } + ] + }, + { + "name": "registerTransceiver", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false, + "docs": [ + "used here that wraps the Transceiver account type." + ] + }, + { + "name": "registeredTransceiver", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setOutboundLimit", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetOutboundLimitArgs" + } + } + ] + }, + { + "name": "setInboundLimit", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetInboundLimitArgs" + } + } + ] + }, + { + "name": "markOutboxItemAsReleased", + "accounts": [ + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": "bool" + }, + { + "name": "setWormholePeer", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetTransceiverPeerArgs" + } + } + ] + }, + { + "name": "receiveWormholeMessage", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "releaseWormholeOutbound", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseOutboundArgs" + } + } + ] + }, + { + "name": "broadcastWormholeId", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "broadcastWormholePeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "BroadcastPeerArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "Config", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "owner", + "docs": [ + "Owner of the program." + ], + "type": "publicKey" + }, + { + "name": "pendingOwner", + "docs": [ + "Pending next owner (before claiming ownership)." + ], + "type": { + "option": "publicKey" + } + }, + { + "name": "mint", + "docs": [ + "Mint address of the token managed by this program." + ], + "type": "publicKey" + }, + { + "name": "tokenProgram", + "docs": [ + "Address of the token program (token or token22). This could always be queried", + "from the [`mint`] account's owner, but storing it here avoids an indirection", + "on the client side." + ], + "type": "publicKey" + }, + { + "name": "mode", + "docs": [ + "The mode that this program is running in. This is used to determine", + "whether the program is burning tokens or locking tokens." + ], + "type": { + "defined": "Mode" + } + }, + { + "name": "chainId", + "docs": [ + "The chain id of the chain that this program is running on. We don't", + "hardcode this so that the program is deployable on any potential SVM", + "forks." + ], + "type": { + "defined": "ChainId" + } + }, + { + "name": "nextTransceiverId", + "docs": [ + "The next transceiver id to use when registering an transceiver." + ], + "type": "u8" + }, + { + "name": "threshold", + "docs": [ + "The number of transceivers that must attest to a transfer before it is", + "accepted." + ], + "type": "u8" + }, + { + "name": "enabledTransceivers", + "docs": [ + "Bitmap of enabled transceivers.", + "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + ], + "type": { + "defined": "Bitmap" + } + }, + { + "name": "paused", + "docs": [ + "Pause the program. This is useful for upgrades and other maintenance." + ], + "type": "bool" + }, + { + "name": "custody", + "docs": [ + "The custody account that holds tokens in locking mode." + ], + "type": "publicKey" + } + ] + } + }, + { + "name": "LUT", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": "publicKey" + } + ] + } + }, + { + "name": "NttManagerPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "tokenDecimals", + "type": "u8" + } + ] + } + }, + { + "name": "InboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "init", + "type": "bool" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipientAddress", + "type": "publicKey" + }, + { + "name": "votes", + "type": { + "defined": "Bitmap" + } + }, + { + "name": "releaseStatus", + "type": { + "defined": "ReleaseStatus" + } + } + ] + } + }, + { + "name": "InboxRateLimit", + "docs": [ + "Inbound rate limit per chain.", + "SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.)" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "rateLimit", + "type": { + "defined": "RateLimitState" + } + } + ] + } + }, + { + "name": "OutboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "TrimmedAmount" + } + }, + { + "name": "sender", + "type": "publicKey" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientNttManager", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "releaseTimestamp", + "type": "i64" + }, + { + "name": "released", + "type": { + "defined": "Bitmap" + } + } + ] + } + }, + { + "name": "OutboxRateLimit", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rateLimit", + "type": { + "defined": "RateLimitState" + } + } + ] + } + }, + { + "name": "RegisteredTransceiver", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "id", + "type": "u8" + }, + { + "name": "transceiverAddress", + "type": "publicKey" + } + ] + } + }, + { + "name": "TransceiverPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BridgeData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetIndex", + "docs": [ + "The current guardian set index, used to decide which signature sets to accept." + ], + "type": "u32" + }, + { + "name": "lastLamports", + "docs": [ + "Lamports in the collection account" + ], + "type": "u64" + }, + { + "name": "config", + "docs": [ + "Bridge configuration, which is set once upon initialization." + ], + "type": { + "defined": "BridgeConfig" + } + } + ] + } + } + ], + "types": [ + { + "name": "Bitmap", + "type": { + "kind": "struct", + "fields": [ + { + "name": "map", + "type": "u128" + } + ] + } + }, + { + "name": "SetInboundLimitArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "type": "u64" + }, + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + } + ] + } + }, + { + "name": "SetOutboundLimitArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "type": "u64" + } + ] + } + }, + { + "name": "SetPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "limit", + "type": "u64" + }, + { + "name": "tokenDecimals", + "docs": [ + "The token decimals on the peer chain." + ], + "type": "u8" + } + ] + } + }, + { + "name": "InitializeArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + }, + { + "name": "limit", + "type": "u64" + }, + { + "name": "mode", + "type": { + "defined": "Mode" + } + } + ] + } + }, + { + "name": "RedeemArgs", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "ReleaseInboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "TransferArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "shouldQueue", + "type": "bool" + } + ] + } + }, + { + "name": "ReleaseStatus", + "docs": [ + "The status of an InboxItem. This determines whether the tokens are minted/unlocked to the recipient. As", + "such, this must be used as a state machine that moves forward in a linear manner. A state", + "should never \"move backward\" to a previous state (e.g. should never move from `Released` to", + "`ReleaseAfter`)." + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "NotApproved" + }, + { + "name": "ReleaseAfter", + "fields": [ + "i64" + ] + }, + { + "name": "Released" + } + ] + } + }, + { + "name": "RateLimitState", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "docs": [ + "The maximum capacity of the rate limiter." + ], + "type": "u64" + }, + { + "name": "capacityAtLastTx", + "docs": [ + "The capacity of the rate limiter at `last_tx_timestamp`.", + "The actual current capacity is calculated in `capacity_at`, by", + "accounting for the time that has passed since `last_tx_timestamp` and", + "the refill rate." + ], + "type": "u64" + }, + { + "name": "lastTxTimestamp", + "docs": [ + "The timestamp of the last transaction that counted towards the current", + "capacity. Transactions that exceeded the capacity do not count, they are", + "just delayed." + ], + "type": "i64" + } + ] + } + }, + { + "name": "SetTransceiverPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BroadcastPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "ReleaseOutboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "ChainId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u16" + } + ] + } + }, + { + "name": "Mode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Locking" + }, + { + "name": "Burning" + } + ] + } + }, + { + "name": "TrimmedAmount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + }, + { + "name": "BridgeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetExpirationTime", + "docs": [ + "Period for how long a guardian set is valid after it has been replaced by a new one. This", + "guarantees that VAAs issued by that set can still be submitted for a certain period. In", + "this period we still trust the old guardian set." + ], + "type": "u32" + }, + { + "name": "fee", + "docs": [ + "Amount of lamports that needs to be paid to the protocol to post a message" + ], + "type": "u64" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "CantReleaseYet", + "msg": "CantReleaseYet" + }, + { + "code": 6001, + "name": "InvalidPendingOwner", + "msg": "InvalidPendingOwner" + }, + { + "code": 6002, + "name": "InvalidChainId", + "msg": "InvalidChainId" + }, + { + "code": 6003, + "name": "InvalidRecipientAddress", + "msg": "InvalidRecipientAddress" + }, + { + "code": 6004, + "name": "InvalidTransceiverPeer", + "msg": "InvalidTransceiverPeer" + }, + { + "code": 6005, + "name": "InvalidNttManagerPeer", + "msg": "InvalidNttManagerPeer" + }, + { + "code": 6006, + "name": "InvalidRecipientNttManager", + "msg": "InvalidRecipientNttManager" + }, + { + "code": 6007, + "name": "TransferAlreadyRedeemed", + "msg": "TransferAlreadyRedeemed" + }, + { + "code": 6008, + "name": "TransferCannotBeRedeemed", + "msg": "TransferCannotBeRedeemed" + }, + { + "code": 6009, + "name": "TransferNotApproved", + "msg": "TransferNotApproved" + }, + { + "code": 6010, + "name": "MessageAlreadySent", + "msg": "MessageAlreadySent" + }, + { + "code": 6011, + "name": "InvalidMode", + "msg": "InvalidMode" + }, + { + "code": 6012, + "name": "InvalidMintAuthority", + "msg": "InvalidMintAuthority" + }, + { + "code": 6013, + "name": "TransferExceedsRateLimit", + "msg": "TransferExceedsRateLimit" + }, + { + "code": 6014, + "name": "Paused", + "msg": "Paused" + }, + { + "code": 6015, + "name": "DisabledTransceiver", + "msg": "DisabledTransceiver" + }, + { + "code": 6016, + "name": "InvalidDeployer", + "msg": "InvalidDeployer" + }, + { + "code": 6017, + "name": "BadAmountAfterTransfer", + "msg": "BadAmountAfterTransfer" + }, + { + "code": 6018, + "name": "BadAmountAfterBurn", + "msg": "BadAmountAfterBurn" + }, + { + "code": 6019, + "name": "ZeroThreshold", + "msg": "ZeroThreshold" + }, + { + "code": 6020, + "name": "OverflowExponent", + "msg": "OverflowExponent" + }, + { + "code": 6021, + "name": "OverflowScaledAmount", + "msg": "OverflowScaledAmount" + }, + { + "code": 6022, + "name": "BitmapIndexOutOfBounds", + "msg": "BitmapIndexOutOfBounds" + }, + { + "code": 6023, + "name": "NoRegisteredTransceivers", + "msg": "NoRegisteredTransceivers" + } + ] +} diff --git a/solana/ts/idl/3_0_0/json/ntt_quoter.json b/solana/ts/idl/3_0_0/json/ntt_quoter.json new file mode 100644 index 000000000..ecf37793e --- /dev/null +++ b/solana/ts/idl/3_0_0/json/ntt_quoter.json @@ -0,0 +1,588 @@ +{ + "version": "3.0.0", + "name": "ntt_quoter", + "instructions": [ + { + "name": "requestRelay", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": false, + "isSigner": false, + "docs": [ + "and checking the release constraint into a single function" + ] + }, + { + "name": "relayRequest", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RequestRelayArgs" + } + } + ] + }, + { + "name": "closeRelay", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": true, + "isSigner": false + }, + { + "name": "relayRequest", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initialize", + "accounts": [ + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false, + "docs": [ + "We use the program data to make sure this owner is the upgrade authority (the true owner,", + "who deployed this program)." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setAssistant", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "assistant", + "isMut": false, + "isSigner": false, + "isOptional": true + } + ], + "args": [] + }, + { + "name": "setFeeRecipient", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "registerChain", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RegisterChainArgs" + } + } + ] + }, + { + "name": "registerNtt", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RegisterNttArgs" + } + } + ] + }, + { + "name": "deregisterNtt", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "DeregisterNttArgs" + } + } + ] + }, + { + "name": "updateSolPrice", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateSolPriceArgs" + } + } + ] + }, + { + "name": "updateChainPrices", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateChainPricesArgs" + } + } + ] + }, + { + "name": "updateChainParams", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateChainParamsArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "Instance", + "type": { + "kind": "struct", + "fields": [ + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "assistant", + "type": "publicKey" + }, + { + "name": "feeRecipient", + "type": "publicKey" + }, + { + "name": "solPrice", + "type": "u64" + } + ] + } + }, + { + "name": "RegisteredChain", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "maxGasDropoff", + "type": "u64" + }, + { + "name": "basePrice", + "type": "u64" + }, + { + "name": "nativePrice", + "type": "u64" + }, + { + "name": "gasPrice", + "type": "u64" + } + ] + } + }, + { + "name": "RegisteredNtt", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "wormholeTransceiverIndex", + "type": "u8" + }, + { + "name": "gasCost", + "type": "u32" + } + ] + } + }, + { + "name": "RelayRequest", + "type": { + "kind": "struct", + "fields": [ + { + "name": "requestedGasDropoff", + "type": "u64" + } + ] + } + } + ], + "types": [ + { + "name": "RegisterChainArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "RegisterNttArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nttProgramId", + "type": "publicKey" + }, + { + "name": "wormholeTransceiverIndex", + "type": "u8" + }, + { + "name": "gasCost", + "type": "u32" + } + ] + } + }, + { + "name": "DeregisterNttArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nttProgramId", + "type": "publicKey" + } + ] + } + }, + { + "name": "RequestRelayArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "gasDropoff", + "type": "u64" + }, + { + "name": "maxFee", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateSolPriceArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "solPrice", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateChainPricesArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nativePrice", + "type": "u64" + }, + { + "name": "gasPrice", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateChainParamsArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxGasDropoff", + "type": "u64" + }, + { + "name": "basePrice", + "type": "u64" + } + ] + } + } + ], + "errors": [ + { + "code": 6001, + "name": "ExceedsUserMaxFee", + "msg": "Relay fees exceeds specified max" + }, + { + "code": 6002, + "name": "ExceedsMaxGasDropoff", + "msg": "Requested gas dropoff exceeds max allowed for chain" + }, + { + "code": 6003, + "name": "InvalidFeeRecipient", + "msg": "The specified fee recipient does not match the address in the instance accound" + }, + { + "code": 6004, + "name": "RelayingToChainDisabled", + "msg": "Relaying to the specified chain is disabled" + }, + { + "code": 6005, + "name": "OutboxItemNotReleased", + "msg": "Relaying to the specified chain is disabled" + }, + { + "code": 6006, + "name": "ScalingOverflow", + "msg": "Scaled value exceeds u64::MAX" + }, + { + "code": 6007, + "name": "DivByZero", + "msg": "Cannot divide by zero" + }, + { + "code": 6257, + "name": "FeeRecipientCannotBeDefault", + "msg": "The fee recipient cannot be the default address (0x0)" + }, + { + "code": 6258, + "name": "NotAuthorized", + "msg": "Must be owner or assistant" + }, + { + "code": 6259, + "name": "PriceCannotBeZero", + "msg": "The price cannot be zero" + } + ] +} diff --git a/solana/ts/idl/3_0_0/json/ntt_transceiver.json b/solana/ts/idl/3_0_0/json/ntt_transceiver.json new file mode 100644 index 000000000..be68fcd81 --- /dev/null +++ b/solana/ts/idl/3_0_0/json/ntt_transceiver.json @@ -0,0 +1,698 @@ +{ + "version": "3.0.0", + "name": "ntt_transceiver", + "instructions": [ + { + "name": "transceiverType", + "accounts": [], + "args": [], + "returns": "string" + }, + { + "name": "setWormholePeer", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetTransceiverPeerArgs" + } + } + ] + }, + { + "name": "receiveWormholeMessage", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "releaseWormholeOutbound", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "manager", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItemSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseOutboundArgs" + } + } + ] + }, + { + "name": "broadcastWormholeId", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "broadcastWormholePeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "BroadcastPeerArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "Config", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "owner", + "docs": [ + "Owner of the program." + ], + "type": "publicKey" + }, + { + "name": "pendingOwner", + "docs": [ + "Pending next owner (before claiming ownership)." + ], + "type": { + "option": "publicKey" + } + }, + { + "name": "mint", + "docs": [ + "Mint address of the token managed by this program." + ], + "type": "publicKey" + }, + { + "name": "tokenProgram", + "docs": [ + "Address of the token program (token or token22). This could always be queried", + "from the [`mint`] account's owner, but storing it here avoids an indirection", + "on the client side." + ], + "type": "publicKey" + }, + { + "name": "mode", + "docs": [ + "The mode that this program is running in. This is used to determine", + "whether the program is burning tokens or locking tokens." + ], + "type": { + "defined": "Mode" + } + }, + { + "name": "chainId", + "docs": [ + "The chain id of the chain that this program is running on. We don't", + "hardcode this so that the program is deployable on any potential SVM", + "forks." + ], + "type": { + "defined": "ChainId" + } + }, + { + "name": "nextTransceiverId", + "docs": [ + "The next transceiver id to use when registering an transceiver." + ], + "type": "u8" + }, + { + "name": "threshold", + "docs": [ + "The number of transceivers that must attest to a transfer before it is", + "accepted." + ], + "type": "u8" + }, + { + "name": "enabledTransceivers", + "docs": [ + "Bitmap of enabled transceivers.", + "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + ], + "type": { + "defined": "Bitmap" + } + }, + { + "name": "paused", + "docs": [ + "Pause the program. This is useful for upgrades and other maintenance." + ], + "type": "bool" + }, + { + "name": "custody", + "docs": [ + "The custody account that holds tokens in locking mode." + ], + "type": "publicKey" + } + ] + } + }, + { + "name": "OutboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "TrimmedAmount" + } + }, + { + "name": "sender", + "type": "publicKey" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientNttManager", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "releaseTimestamp", + "type": "i64" + }, + { + "name": "released", + "type": { + "defined": "Bitmap" + } + } + ] + } + }, + { + "name": "RegisteredTransceiver", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "id", + "type": "u8" + }, + { + "name": "transceiverAddress", + "type": "publicKey" + } + ] + } + }, + { + "name": "TransceiverPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BridgeData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetIndex", + "docs": [ + "The current guardian set index, used to decide which signature sets to accept." + ], + "type": "u32" + }, + { + "name": "lastLamports", + "docs": [ + "Lamports in the collection account" + ], + "type": "u64" + }, + { + "name": "config", + "docs": [ + "Bridge configuration, which is set once upon initialization." + ], + "type": { + "defined": "BridgeConfig" + } + } + ] + } + } + ], + "types": [ + { + "name": "Bitmap", + "type": { + "kind": "struct", + "fields": [ + { + "name": "map", + "type": "u128" + } + ] + } + }, + { + "name": "ChainId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u16" + } + ] + } + }, + { + "name": "Mode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Locking" + }, + { + "name": "Burning" + } + ] + } + }, + { + "name": "TrimmedAmount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + }, + { + "name": "SetTransceiverPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BroadcastPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "ReleaseOutboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "BridgeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetExpirationTime", + "docs": [ + "Period for how long a guardian set is valid after it has been replaced by a new one. This", + "guarantees that VAAs issued by that set can still be submitted for a certain period. In", + "this period we still trust the old guardian set." + ], + "type": "u32" + }, + { + "name": "fee", + "docs": [ + "Amount of lamports that needs to be paid to the protocol to post a message" + ], + "type": "u64" + } + ] + } + } + ] +} diff --git a/solana/ts/idl/3_0_0/json/wormhole_governance.json b/solana/ts/idl/3_0_0/json/wormhole_governance.json new file mode 100644 index 000000000..f6f61f6ec --- /dev/null +++ b/solana/ts/idl/3_0_0/json/wormhole_governance.json @@ -0,0 +1,76 @@ +{ + "version": "3.0.0", + "name": "wormhole_governance", + "instructions": [ + { + "name": "governance", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "governance", + "isMut": true, + "isSigner": false, + "docs": [ + "governed program. This account is validated by Wormhole, not this program." + ] + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "replay", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "ReplayProtection", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "InvalidGovernanceChain", + "msg": "InvalidGovernanceChain" + }, + { + "code": 6001, + "name": "InvalidGovernanceEmitter", + "msg": "InvalidGovernanceEmitter" + }, + { + "code": 6002, + "name": "InvalidGovernanceProgram", + "msg": "InvalidGovernanceProgram" + } + ] +} \ No newline at end of file diff --git a/solana/ts/idl/3_0_0/ts/dummy_transfer_hook.ts b/solana/ts/idl/3_0_0/ts/dummy_transfer_hook.ts new file mode 100644 index 000000000..1c494bbd4 --- /dev/null +++ b/solana/ts/idl/3_0_0/ts/dummy_transfer_hook.ts @@ -0,0 +1,221 @@ +export type DummyTransferHook = { + "version": "3.0.0", + "name": "dummy_transfer_hook", + "instructions": [ + { + "name": "initializeExtraAccountMetaList", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "extraAccountMetaList", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "counter", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferHook", + "accounts": [ + { + "name": "sourceToken", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "destinationToken", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "extraAccountMetaList", + "isMut": false, + "isSigner": false + }, + { + "name": "dummyAccount", + "isMut": false, + "isSigner": false, + "docs": [ + "computes and the on-chain code correctly passes on the PDA." + ] + }, + { + "name": "counter", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "counter", + "type": { + "kind": "struct", + "fields": [ + { + "name": "count", + "type": "u64" + } + ] + } + } + ] +} +export const IDL: DummyTransferHook = { + "version": "3.0.0", + "name": "dummy_transfer_hook", + "instructions": [ + { + "name": "initializeExtraAccountMetaList", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "extraAccountMetaList", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "counter", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferHook", + "accounts": [ + { + "name": "sourceToken", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "destinationToken", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "extraAccountMetaList", + "isMut": false, + "isSigner": false + }, + { + "name": "dummyAccount", + "isMut": false, + "isSigner": false, + "docs": [ + "computes and the on-chain code correctly passes on the PDA." + ] + }, + { + "name": "counter", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "counter", + "type": { + "kind": "struct", + "fields": [ + { + "name": "count", + "type": "u64" + } + ] + } + } + ] +} + diff --git a/solana/ts/idl/3_0_0/ts/example_native_token_transfers.ts b/solana/ts/idl/3_0_0/ts/example_native_token_transfers.ts new file mode 100644 index 000000000..6c8a7fce3 --- /dev/null +++ b/solana/ts/idl/3_0_0/ts/example_native_token_transfers.ts @@ -0,0 +1,4049 @@ +export type ExampleNativeTokenTransfers = { + "version": "3.0.0", + "name": "example_native_token_transfers", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "deployer", + "isMut": false, + "isSigner": true + }, + { + "name": "programData", + "isMut": false, + "isSigner": false + }, + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "In any case, this function is used to set the Config and initialize the program so we", + "assume the caller of this function will have total control over the program.", + "", + "TODO: Using `UncheckedAccount` here leads to \"Access violation in stack frame ...\".", + "Could refactor code to use `Box<_>` to reduce stack size." + ] + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "The custody account that holds tokens in locking mode and temporarily", + "holds tokens in burning mode.", + "function if the token account has already been created." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "associated token account for the given mint." + ] + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "InitializeArgs" + } + } + ] + }, + { + "name": "initializeLut", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "lutAddress", + "isMut": true, + "isSigner": false + }, + { + "name": "lut", + "isMut": true, + "isSigner": false + }, + { + "name": "lutProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "entries", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxRateLimit", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ] + } + ], + "args": [ + { + "name": "recentSlot", + "type": "u64" + } + ] + }, + { + "name": "version", + "accounts": [], + "args": [], + "returns": "string" + }, + { + "name": "transferBurn", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false, + "docs": [ + "account can spend these tokens." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": true + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "Tokens are always transferred to the custody account first regardless of", + "the mode.", + "For an explanation, see the note in [`transfer_burn`]." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "sessionAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." + ] + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "TransferArgs" + } + } + ] + }, + { + "name": "transferLock", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false, + "docs": [ + "account can spend these tokens." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": true + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "Tokens are always transferred to the custody account first regardless of", + "the mode.", + "For an explanation, see the note in [`transfer_burn`]." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "sessionAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "TransferArgs" + } + } + ] + }, + { + "name": "redeem", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": false, + "isSigner": false, + "docs": [ + "`Account` and `owner` constraints are mutually-exclusive" + ] + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false, + "docs": [ + "NOTE: This account is content-addressed (PDA seeded by the message hash).", + "This is because in a multi-transceiver configuration, the different", + "transceivers \"vote\" on messages (by delivering them). By making the inbox", + "items content-addressed, we can ensure that disagreeing votes don't", + "interfere with each other.", + "On the first call to [`redeem()`], [`InboxItem`] will be allocated and initialized with", + "default values.", + "On subsequent calls, we want to modify the `InboxItem` by \"voting\" on it. Therefore the", + "program should not fail which would occur when using the `init` constraint.", + "The [`InboxItem::init`] field is used to guard against malicious or accidental modification", + "InboxItem fields that should remain constant." + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RedeemArgs" + } + } + ] + }, + { + "name": "releaseInboundMint", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "CHECK The seeds constraint ensures that this is the correct address" + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseInboundArgs" + } + } + ] + }, + { + "name": "releaseInboundUnlock", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "CHECK The seeds constraint ensures that this is the correct address" + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseInboundArgs" + } + } + ] + }, + { + "name": "transferOwnership", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferOwnershipOneStepUnchecked", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "claimOwnership", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": true + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setPaused", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pause", + "type": "bool" + } + ] + }, + { + "name": "setPeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetPeerArgs" + } + } + ] + }, + { + "name": "registerTransceiver", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false, + "docs": [ + "used here that wraps the Transceiver account type." + ] + }, + { + "name": "registeredTransceiver", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setOutboundLimit", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetOutboundLimitArgs" + } + } + ] + }, + { + "name": "setInboundLimit", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetInboundLimitArgs" + } + } + ] + }, + { + "name": "markOutboxItemAsReleased", + "accounts": [ + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": "bool" + }, + { + "name": "setWormholePeer", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetTransceiverPeerArgs" + } + } + ] + }, + { + "name": "receiveWormholeMessage", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "releaseWormholeOutbound", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseOutboundArgs" + } + } + ] + }, + { + "name": "broadcastWormholeId", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "broadcastWormholePeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "BroadcastPeerArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "config", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "owner", + "docs": [ + "Owner of the program." + ], + "type": "publicKey" + }, + { + "name": "pendingOwner", + "docs": [ + "Pending next owner (before claiming ownership)." + ], + "type": { + "option": "publicKey" + } + }, + { + "name": "mint", + "docs": [ + "Mint address of the token managed by this program." + ], + "type": "publicKey" + }, + { + "name": "tokenProgram", + "docs": [ + "Address of the token program (token or token22). This could always be queried", + "from the [`mint`] account's owner, but storing it here avoids an indirection", + "on the client side." + ], + "type": "publicKey" + }, + { + "name": "mode", + "docs": [ + "The mode that this program is running in. This is used to determine", + "whether the program is burning tokens or locking tokens." + ], + "type": { + "defined": "Mode" + } + }, + { + "name": "chainId", + "docs": [ + "The chain id of the chain that this program is running on. We don't", + "hardcode this so that the program is deployable on any potential SVM", + "forks." + ], + "type": { + "defined": "ChainId" + } + }, + { + "name": "nextTransceiverId", + "docs": [ + "The next transceiver id to use when registering an transceiver." + ], + "type": "u8" + }, + { + "name": "threshold", + "docs": [ + "The number of transceivers that must attest to a transfer before it is", + "accepted." + ], + "type": "u8" + }, + { + "name": "enabledTransceivers", + "docs": [ + "Bitmap of enabled transceivers.", + "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + ], + "type": { + "defined": "Bitmap" + } + }, + { + "name": "paused", + "docs": [ + "Pause the program. This is useful for upgrades and other maintenance." + ], + "type": "bool" + }, + { + "name": "custody", + "docs": [ + "The custody account that holds tokens in locking mode." + ], + "type": "publicKey" + } + ] + } + }, + { + "name": "LUT", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": "publicKey" + } + ] + } + }, + { + "name": "nttManagerPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "tokenDecimals", + "type": "u8" + } + ] + } + }, + { + "name": "inboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "init", + "type": "bool" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipientAddress", + "type": "publicKey" + }, + { + "name": "votes", + "type": { + "defined": "Bitmap" + } + }, + { + "name": "releaseStatus", + "type": { + "defined": "ReleaseStatus" + } + } + ] + } + }, + { + "name": "inboxRateLimit", + "docs": [ + "Inbound rate limit per chain.", + "SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.)" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "rateLimit", + "type": { + "defined": "RateLimitState" + } + } + ] + } + }, + { + "name": "outboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "TrimmedAmount" + } + }, + { + "name": "sender", + "type": "publicKey" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientNttManager", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "releaseTimestamp", + "type": "i64" + }, + { + "name": "released", + "type": { + "defined": "Bitmap" + } + } + ] + } + }, + { + "name": "outboxRateLimit", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rateLimit", + "type": { + "defined": "RateLimitState" + } + } + ] + } + }, + { + "name": "registeredTransceiver", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "id", + "type": "u8" + }, + { + "name": "transceiverAddress", + "type": "publicKey" + } + ] + } + }, + { + "name": "transceiverPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "bridgeData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetIndex", + "docs": [ + "The current guardian set index, used to decide which signature sets to accept." + ], + "type": "u32" + }, + { + "name": "lastLamports", + "docs": [ + "Lamports in the collection account" + ], + "type": "u64" + }, + { + "name": "config", + "docs": [ + "Bridge configuration, which is set once upon initialization." + ], + "type": { + "defined": "BridgeConfig" + } + } + ] + } + } + ], + "types": [ + { + "name": "Bitmap", + "type": { + "kind": "struct", + "fields": [ + { + "name": "map", + "type": "u128" + } + ] + } + }, + { + "name": "SetInboundLimitArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "type": "u64" + }, + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + } + ] + } + }, + { + "name": "SetOutboundLimitArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "type": "u64" + } + ] + } + }, + { + "name": "SetPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "limit", + "type": "u64" + }, + { + "name": "tokenDecimals", + "docs": [ + "The token decimals on the peer chain." + ], + "type": "u8" + } + ] + } + }, + { + "name": "InitializeArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + }, + { + "name": "limit", + "type": "u64" + }, + { + "name": "mode", + "type": { + "defined": "Mode" + } + } + ] + } + }, + { + "name": "RedeemArgs", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "ReleaseInboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "TransferArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "shouldQueue", + "type": "bool" + } + ] + } + }, + { + "name": "ReleaseStatus", + "docs": [ + "The status of an InboxItem. This determines whether the tokens are minted/unlocked to the recipient. As", + "such, this must be used as a state machine that moves forward in a linear manner. A state", + "should never \"move backward\" to a previous state (e.g. should never move from `Released` to", + "`ReleaseAfter`)." + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "NotApproved" + }, + { + "name": "ReleaseAfter", + "fields": [ + "i64" + ] + }, + { + "name": "Released" + } + ] + } + }, + { + "name": "RateLimitState", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "docs": [ + "The maximum capacity of the rate limiter." + ], + "type": "u64" + }, + { + "name": "capacityAtLastTx", + "docs": [ + "The capacity of the rate limiter at `last_tx_timestamp`.", + "The actual current capacity is calculated in `capacity_at`, by", + "accounting for the time that has passed since `last_tx_timestamp` and", + "the refill rate." + ], + "type": "u64" + }, + { + "name": "lastTxTimestamp", + "docs": [ + "The timestamp of the last transaction that counted towards the current", + "capacity. Transactions that exceeded the capacity do not count, they are", + "just delayed." + ], + "type": "i64" + } + ] + } + }, + { + "name": "SetTransceiverPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BroadcastPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "ReleaseOutboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "ChainId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u16" + } + ] + } + }, + { + "name": "Mode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Locking" + }, + { + "name": "Burning" + } + ] + } + }, + { + "name": "TrimmedAmount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + }, + { + "name": "BridgeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetExpirationTime", + "docs": [ + "Period for how long a guardian set is valid after it has been replaced by a new one. This", + "guarantees that VAAs issued by that set can still be submitted for a certain period. In", + "this period we still trust the old guardian set." + ], + "type": "u32" + }, + { + "name": "fee", + "docs": [ + "Amount of lamports that needs to be paid to the protocol to post a message" + ], + "type": "u64" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "CantReleaseYet", + "msg": "CantReleaseYet" + }, + { + "code": 6001, + "name": "InvalidPendingOwner", + "msg": "InvalidPendingOwner" + }, + { + "code": 6002, + "name": "InvalidChainId", + "msg": "InvalidChainId" + }, + { + "code": 6003, + "name": "InvalidRecipientAddress", + "msg": "InvalidRecipientAddress" + }, + { + "code": 6004, + "name": "InvalidTransceiverPeer", + "msg": "InvalidTransceiverPeer" + }, + { + "code": 6005, + "name": "InvalidNttManagerPeer", + "msg": "InvalidNttManagerPeer" + }, + { + "code": 6006, + "name": "InvalidRecipientNttManager", + "msg": "InvalidRecipientNttManager" + }, + { + "code": 6007, + "name": "TransferAlreadyRedeemed", + "msg": "TransferAlreadyRedeemed" + }, + { + "code": 6008, + "name": "TransferCannotBeRedeemed", + "msg": "TransferCannotBeRedeemed" + }, + { + "code": 6009, + "name": "TransferNotApproved", + "msg": "TransferNotApproved" + }, + { + "code": 6010, + "name": "MessageAlreadySent", + "msg": "MessageAlreadySent" + }, + { + "code": 6011, + "name": "InvalidMode", + "msg": "InvalidMode" + }, + { + "code": 6012, + "name": "InvalidMintAuthority", + "msg": "InvalidMintAuthority" + }, + { + "code": 6013, + "name": "TransferExceedsRateLimit", + "msg": "TransferExceedsRateLimit" + }, + { + "code": 6014, + "name": "Paused", + "msg": "Paused" + }, + { + "code": 6015, + "name": "DisabledTransceiver", + "msg": "DisabledTransceiver" + }, + { + "code": 6016, + "name": "InvalidDeployer", + "msg": "InvalidDeployer" + }, + { + "code": 6017, + "name": "BadAmountAfterTransfer", + "msg": "BadAmountAfterTransfer" + }, + { + "code": 6018, + "name": "BadAmountAfterBurn", + "msg": "BadAmountAfterBurn" + }, + { + "code": 6019, + "name": "ZeroThreshold", + "msg": "ZeroThreshold" + }, + { + "code": 6020, + "name": "OverflowExponent", + "msg": "OverflowExponent" + }, + { + "code": 6021, + "name": "OverflowScaledAmount", + "msg": "OverflowScaledAmount" + }, + { + "code": 6022, + "name": "BitmapIndexOutOfBounds", + "msg": "BitmapIndexOutOfBounds" + }, + { + "code": 6023, + "name": "NoRegisteredTransceivers", + "msg": "NoRegisteredTransceivers" + } + ] +} +export const IDL: ExampleNativeTokenTransfers = { + "version": "3.0.0", + "name": "example_native_token_transfers", + "instructions": [ + { + "name": "initialize", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "deployer", + "isMut": false, + "isSigner": true + }, + { + "name": "programData", + "isMut": false, + "isSigner": false + }, + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "In any case, this function is used to set the Config and initialize the program so we", + "assume the caller of this function will have total control over the program.", + "", + "TODO: Using `UncheckedAccount` here leads to \"Access violation in stack frame ...\".", + "Could refactor code to use `Box<_>` to reduce stack size." + ] + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "The custody account that holds tokens in locking mode and temporarily", + "holds tokens in burning mode.", + "function if the token account has already been created." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "associated token account for the given mint." + ] + }, + { + "name": "associatedTokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "InitializeArgs" + } + } + ] + }, + { + "name": "initializeLut", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "authority", + "isMut": false, + "isSigner": false + }, + { + "name": "lutAddress", + "isMut": true, + "isSigner": false + }, + { + "name": "lut", + "isMut": true, + "isSigner": false + }, + { + "name": "lutProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "entries", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxRateLimit", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ] + } + ], + "args": [ + { + "name": "recentSlot", + "type": "u64" + } + ] + }, + { + "name": "version", + "accounts": [], + "args": [], + "returns": "string" + }, + { + "name": "transferBurn", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false, + "docs": [ + "account can spend these tokens." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": true + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "Tokens are always transferred to the custody account first regardless of", + "the mode.", + "For an explanation, see the note in [`transfer_burn`]." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "sessionAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." + ] + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "TransferArgs" + } + } + ] + }, + { + "name": "transferLock", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "from", + "isMut": true, + "isSigner": false, + "docs": [ + "account can spend these tokens." + ] + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": true + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false, + "docs": [ + "Tokens are always transferred to the custody account first regardless of", + "the mode.", + "For an explanation, see the note in [`transfer_burn`]." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "sessionAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "See [`crate::SESSION_AUTHORITY_SEED`] for an explanation of the flow." + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "TransferArgs" + } + } + ] + }, + { + "name": "redeem", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": false, + "isSigner": false, + "docs": [ + "`Account` and `owner` constraints are mutually-exclusive" + ] + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false, + "docs": [ + "NOTE: This account is content-addressed (PDA seeded by the message hash).", + "This is because in a multi-transceiver configuration, the different", + "transceivers \"vote\" on messages (by delivering them). By making the inbox", + "items content-addressed, we can ensure that disagreeing votes don't", + "interfere with each other.", + "On the first call to [`redeem()`], [`InboxItem`] will be allocated and initialized with", + "default values.", + "On subsequent calls, we want to modify the `InboxItem` by \"voting\" on it. Therefore the", + "program should not fail which would occur when using the `init` constraint.", + "The [`InboxItem::init`] field is used to guard against malicious or accidental modification", + "InboxItem fields that should remain constant." + ] + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "outboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RedeemArgs" + } + } + ] + }, + { + "name": "releaseInboundMint", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "CHECK The seeds constraint ensures that this is the correct address" + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseInboundArgs" + } + } + ] + }, + { + "name": "releaseInboundUnlock", + "accounts": [ + { + "name": "common", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "inboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "recipient", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenAuthority", + "isMut": false, + "isSigner": false, + "docs": [ + "CHECK The seeds constraint ensures that this is the correct address" + ] + }, + { + "name": "mint", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "custody", + "isMut": true, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseInboundArgs" + } + } + ] + }, + { + "name": "transferOwnership", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "transferOwnershipOneStepUnchecked", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "claimOwnership", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "upgradeLock", + "isMut": false, + "isSigner": false + }, + { + "name": "newOwner", + "isMut": false, + "isSigner": true + }, + { + "name": "programData", + "isMut": true, + "isSigner": false + }, + { + "name": "bpfLoaderUpgradeableProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setPaused", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pause", + "type": "bool" + } + ] + }, + { + "name": "setPeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "inboxRateLimit", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetPeerArgs" + } + } + ] + }, + { + "name": "registerTransceiver", + "accounts": [ + { + "name": "config", + "isMut": true, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false, + "docs": [ + "used here that wraps the Transceiver account type." + ] + }, + { + "name": "registeredTransceiver", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setOutboundLimit", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetOutboundLimitArgs" + } + } + ] + }, + { + "name": "setInboundLimit", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "rateLimit", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetInboundLimitArgs" + } + } + ] + }, + { + "name": "markOutboxItemAsReleased", + "accounts": [ + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + } + ], + "args": [], + "returns": "bool" + }, + { + "name": "setWormholePeer", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetTransceiverPeerArgs" + } + } + ] + }, + { + "name": "receiveWormholeMessage", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "releaseWormholeOutbound", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseOutboundArgs" + } + } + ] + }, + { + "name": "broadcastWormholeId", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "broadcastWormholePeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "BroadcastPeerArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "config", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "owner", + "docs": [ + "Owner of the program." + ], + "type": "publicKey" + }, + { + "name": "pendingOwner", + "docs": [ + "Pending next owner (before claiming ownership)." + ], + "type": { + "option": "publicKey" + } + }, + { + "name": "mint", + "docs": [ + "Mint address of the token managed by this program." + ], + "type": "publicKey" + }, + { + "name": "tokenProgram", + "docs": [ + "Address of the token program (token or token22). This could always be queried", + "from the [`mint`] account's owner, but storing it here avoids an indirection", + "on the client side." + ], + "type": "publicKey" + }, + { + "name": "mode", + "docs": [ + "The mode that this program is running in. This is used to determine", + "whether the program is burning tokens or locking tokens." + ], + "type": { + "defined": "Mode" + } + }, + { + "name": "chainId", + "docs": [ + "The chain id of the chain that this program is running on. We don't", + "hardcode this so that the program is deployable on any potential SVM", + "forks." + ], + "type": { + "defined": "ChainId" + } + }, + { + "name": "nextTransceiverId", + "docs": [ + "The next transceiver id to use when registering an transceiver." + ], + "type": "u8" + }, + { + "name": "threshold", + "docs": [ + "The number of transceivers that must attest to a transfer before it is", + "accepted." + ], + "type": "u8" + }, + { + "name": "enabledTransceivers", + "docs": [ + "Bitmap of enabled transceivers.", + "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + ], + "type": { + "defined": "Bitmap" + } + }, + { + "name": "paused", + "docs": [ + "Pause the program. This is useful for upgrades and other maintenance." + ], + "type": "bool" + }, + { + "name": "custody", + "docs": [ + "The custody account that holds tokens in locking mode." + ], + "type": "publicKey" + } + ] + } + }, + { + "name": "LUT", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": "publicKey" + } + ] + } + }, + { + "name": "nttManagerPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "tokenDecimals", + "type": "u8" + } + ] + } + }, + { + "name": "inboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "init", + "type": "bool" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipientAddress", + "type": "publicKey" + }, + { + "name": "votes", + "type": { + "defined": "Bitmap" + } + }, + { + "name": "releaseStatus", + "type": { + "defined": "ReleaseStatus" + } + } + ] + } + }, + { + "name": "inboxRateLimit", + "docs": [ + "Inbound rate limit per chain.", + "SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.)" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "rateLimit", + "type": { + "defined": "RateLimitState" + } + } + ] + } + }, + { + "name": "outboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "TrimmedAmount" + } + }, + { + "name": "sender", + "type": "publicKey" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientNttManager", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "releaseTimestamp", + "type": "i64" + }, + { + "name": "released", + "type": { + "defined": "Bitmap" + } + } + ] + } + }, + { + "name": "outboxRateLimit", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rateLimit", + "type": { + "defined": "RateLimitState" + } + } + ] + } + }, + { + "name": "registeredTransceiver", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "id", + "type": "u8" + }, + { + "name": "transceiverAddress", + "type": "publicKey" + } + ] + } + }, + { + "name": "transceiverPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "bridgeData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetIndex", + "docs": [ + "The current guardian set index, used to decide which signature sets to accept." + ], + "type": "u32" + }, + { + "name": "lastLamports", + "docs": [ + "Lamports in the collection account" + ], + "type": "u64" + }, + { + "name": "config", + "docs": [ + "Bridge configuration, which is set once upon initialization." + ], + "type": { + "defined": "BridgeConfig" + } + } + ] + } + } + ], + "types": [ + { + "name": "Bitmap", + "type": { + "kind": "struct", + "fields": [ + { + "name": "map", + "type": "u128" + } + ] + } + }, + { + "name": "SetInboundLimitArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "type": "u64" + }, + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + } + ] + } + }, + { + "name": "SetOutboundLimitArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "type": "u64" + } + ] + } + }, + { + "name": "SetPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "limit", + "type": "u64" + }, + { + "name": "tokenDecimals", + "docs": [ + "The token decimals on the peer chain." + ], + "type": "u8" + } + ] + } + }, + { + "name": "InitializeArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + }, + { + "name": "limit", + "type": "u64" + }, + { + "name": "mode", + "type": { + "defined": "Mode" + } + } + ] + } + }, + { + "name": "RedeemArgs", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "ReleaseInboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "TransferArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "shouldQueue", + "type": "bool" + } + ] + } + }, + { + "name": "ReleaseStatus", + "docs": [ + "The status of an InboxItem. This determines whether the tokens are minted/unlocked to the recipient. As", + "such, this must be used as a state machine that moves forward in a linear manner. A state", + "should never \"move backward\" to a previous state (e.g. should never move from `Released` to", + "`ReleaseAfter`)." + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "NotApproved" + }, + { + "name": "ReleaseAfter", + "fields": [ + "i64" + ] + }, + { + "name": "Released" + } + ] + } + }, + { + "name": "RateLimitState", + "type": { + "kind": "struct", + "fields": [ + { + "name": "limit", + "docs": [ + "The maximum capacity of the rate limiter." + ], + "type": "u64" + }, + { + "name": "capacityAtLastTx", + "docs": [ + "The capacity of the rate limiter at `last_tx_timestamp`.", + "The actual current capacity is calculated in `capacity_at`, by", + "accounting for the time that has passed since `last_tx_timestamp` and", + "the refill rate." + ], + "type": "u64" + }, + { + "name": "lastTxTimestamp", + "docs": [ + "The timestamp of the last transaction that counted towards the current", + "capacity. Transactions that exceeded the capacity do not count, they are", + "just delayed." + ], + "type": "i64" + } + ] + } + }, + { + "name": "SetTransceiverPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BroadcastPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "ReleaseOutboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "ChainId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u16" + } + ] + } + }, + { + "name": "Mode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Locking" + }, + { + "name": "Burning" + } + ] + } + }, + { + "name": "TrimmedAmount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + }, + { + "name": "BridgeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetExpirationTime", + "docs": [ + "Period for how long a guardian set is valid after it has been replaced by a new one. This", + "guarantees that VAAs issued by that set can still be submitted for a certain period. In", + "this period we still trust the old guardian set." + ], + "type": "u32" + }, + { + "name": "fee", + "docs": [ + "Amount of lamports that needs to be paid to the protocol to post a message" + ], + "type": "u64" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "CantReleaseYet", + "msg": "CantReleaseYet" + }, + { + "code": 6001, + "name": "InvalidPendingOwner", + "msg": "InvalidPendingOwner" + }, + { + "code": 6002, + "name": "InvalidChainId", + "msg": "InvalidChainId" + }, + { + "code": 6003, + "name": "InvalidRecipientAddress", + "msg": "InvalidRecipientAddress" + }, + { + "code": 6004, + "name": "InvalidTransceiverPeer", + "msg": "InvalidTransceiverPeer" + }, + { + "code": 6005, + "name": "InvalidNttManagerPeer", + "msg": "InvalidNttManagerPeer" + }, + { + "code": 6006, + "name": "InvalidRecipientNttManager", + "msg": "InvalidRecipientNttManager" + }, + { + "code": 6007, + "name": "TransferAlreadyRedeemed", + "msg": "TransferAlreadyRedeemed" + }, + { + "code": 6008, + "name": "TransferCannotBeRedeemed", + "msg": "TransferCannotBeRedeemed" + }, + { + "code": 6009, + "name": "TransferNotApproved", + "msg": "TransferNotApproved" + }, + { + "code": 6010, + "name": "MessageAlreadySent", + "msg": "MessageAlreadySent" + }, + { + "code": 6011, + "name": "InvalidMode", + "msg": "InvalidMode" + }, + { + "code": 6012, + "name": "InvalidMintAuthority", + "msg": "InvalidMintAuthority" + }, + { + "code": 6013, + "name": "TransferExceedsRateLimit", + "msg": "TransferExceedsRateLimit" + }, + { + "code": 6014, + "name": "Paused", + "msg": "Paused" + }, + { + "code": 6015, + "name": "DisabledTransceiver", + "msg": "DisabledTransceiver" + }, + { + "code": 6016, + "name": "InvalidDeployer", + "msg": "InvalidDeployer" + }, + { + "code": 6017, + "name": "BadAmountAfterTransfer", + "msg": "BadAmountAfterTransfer" + }, + { + "code": 6018, + "name": "BadAmountAfterBurn", + "msg": "BadAmountAfterBurn" + }, + { + "code": 6019, + "name": "ZeroThreshold", + "msg": "ZeroThreshold" + }, + { + "code": 6020, + "name": "OverflowExponent", + "msg": "OverflowExponent" + }, + { + "code": 6021, + "name": "OverflowScaledAmount", + "msg": "OverflowScaledAmount" + }, + { + "code": 6022, + "name": "BitmapIndexOutOfBounds", + "msg": "BitmapIndexOutOfBounds" + }, + { + "code": 6023, + "name": "NoRegisteredTransceivers", + "msg": "NoRegisteredTransceivers" + } + ] +} + diff --git a/solana/ts/idl/3_0_0/ts/ntt_quoter.ts b/solana/ts/idl/3_0_0/ts/ntt_quoter.ts new file mode 100644 index 000000000..161bf03aa --- /dev/null +++ b/solana/ts/idl/3_0_0/ts/ntt_quoter.ts @@ -0,0 +1,1177 @@ +export type NttQuoter = { + "version": "3.0.0", + "name": "ntt_quoter", + "instructions": [ + { + "name": "requestRelay", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": false, + "isSigner": false, + "docs": [ + "and checking the release constraint into a single function" + ] + }, + { + "name": "relayRequest", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RequestRelayArgs" + } + } + ] + }, + { + "name": "closeRelay", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": true, + "isSigner": false + }, + { + "name": "relayRequest", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initialize", + "accounts": [ + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false, + "docs": [ + "We use the program data to make sure this owner is the upgrade authority (the true owner,", + "who deployed this program)." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setAssistant", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "assistant", + "isMut": false, + "isSigner": false, + "isOptional": true + } + ], + "args": [] + }, + { + "name": "setFeeRecipient", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "registerChain", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RegisterChainArgs" + } + } + ] + }, + { + "name": "registerNtt", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RegisterNttArgs" + } + } + ] + }, + { + "name": "deregisterNtt", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "DeregisterNttArgs" + } + } + ] + }, + { + "name": "updateSolPrice", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateSolPriceArgs" + } + } + ] + }, + { + "name": "updateChainPrices", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateChainPricesArgs" + } + } + ] + }, + { + "name": "updateChainParams", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateChainParamsArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "instance", + "type": { + "kind": "struct", + "fields": [ + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "assistant", + "type": "publicKey" + }, + { + "name": "feeRecipient", + "type": "publicKey" + }, + { + "name": "solPrice", + "type": "u64" + } + ] + } + }, + { + "name": "registeredChain", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "maxGasDropoff", + "type": "u64" + }, + { + "name": "basePrice", + "type": "u64" + }, + { + "name": "nativePrice", + "type": "u64" + }, + { + "name": "gasPrice", + "type": "u64" + } + ] + } + }, + { + "name": "registeredNtt", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "wormholeTransceiverIndex", + "type": "u8" + }, + { + "name": "gasCost", + "type": "u32" + } + ] + } + }, + { + "name": "relayRequest", + "type": { + "kind": "struct", + "fields": [ + { + "name": "requestedGasDropoff", + "type": "u64" + } + ] + } + } + ], + "types": [ + { + "name": "RegisterChainArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "RegisterNttArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nttProgramId", + "type": "publicKey" + }, + { + "name": "wormholeTransceiverIndex", + "type": "u8" + }, + { + "name": "gasCost", + "type": "u32" + } + ] + } + }, + { + "name": "DeregisterNttArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nttProgramId", + "type": "publicKey" + } + ] + } + }, + { + "name": "RequestRelayArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "gasDropoff", + "type": "u64" + }, + { + "name": "maxFee", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateSolPriceArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "solPrice", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateChainPricesArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nativePrice", + "type": "u64" + }, + { + "name": "gasPrice", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateChainParamsArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxGasDropoff", + "type": "u64" + }, + { + "name": "basePrice", + "type": "u64" + } + ] + } + } + ], + "errors": [ + { + "code": 6001, + "name": "ExceedsUserMaxFee", + "msg": "Relay fees exceeds specified max" + }, + { + "code": 6002, + "name": "ExceedsMaxGasDropoff", + "msg": "Requested gas dropoff exceeds max allowed for chain" + }, + { + "code": 6003, + "name": "InvalidFeeRecipient", + "msg": "The specified fee recipient does not match the address in the instance accound" + }, + { + "code": 6004, + "name": "RelayingToChainDisabled", + "msg": "Relaying to the specified chain is disabled" + }, + { + "code": 6005, + "name": "OutboxItemNotReleased", + "msg": "Relaying to the specified chain is disabled" + }, + { + "code": 6006, + "name": "ScalingOverflow", + "msg": "Scaled value exceeds u64::MAX" + }, + { + "code": 6007, + "name": "DivByZero", + "msg": "Cannot divide by zero" + }, + { + "code": 6257, + "name": "FeeRecipientCannotBeDefault", + "msg": "The fee recipient cannot be the default address (0x0)" + }, + { + "code": 6258, + "name": "NotAuthorized", + "msg": "Must be owner or assistant" + }, + { + "code": 6259, + "name": "PriceCannotBeZero", + "msg": "The price cannot be zero" + } + ] +} +export const IDL: NttQuoter = { + "version": "3.0.0", + "name": "ntt_quoter", + "instructions": [ + { + "name": "requestRelay", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItem", + "isMut": false, + "isSigner": false, + "docs": [ + "and checking the release constraint into a single function" + ] + }, + { + "name": "relayRequest", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RequestRelayArgs" + } + } + ] + }, + { + "name": "closeRelay", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": true, + "isSigner": false + }, + { + "name": "relayRequest", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initialize", + "accounts": [ + { + "name": "owner", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": false, + "isSigner": false + }, + { + "name": "programData", + "isMut": true, + "isSigner": false, + "docs": [ + "We use the program data to make sure this owner is the upgrade authority (the true owner,", + "who deployed this program)." + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "setAssistant", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "assistant", + "isMut": false, + "isSigner": false, + "isOptional": true + } + ], + "args": [] + }, + { + "name": "setFeeRecipient", + "accounts": [ + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + }, + { + "name": "feeRecipient", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "registerChain", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RegisterChainArgs" + } + } + ] + }, + { + "name": "registerNtt", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "RegisterNttArgs" + } + } + ] + }, + { + "name": "deregisterNtt", + "accounts": [ + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredNtt", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "DeregisterNttArgs" + } + } + ] + }, + { + "name": "updateSolPrice", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateSolPriceArgs" + } + } + ] + }, + { + "name": "updateChainPrices", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateChainPricesArgs" + } + } + ] + }, + { + "name": "updateChainParams", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "instance", + "isMut": false, + "isSigner": false + }, + { + "name": "registeredChain", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "UpdateChainParamsArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "instance", + "type": { + "kind": "struct", + "fields": [ + { + "name": "owner", + "type": "publicKey" + }, + { + "name": "assistant", + "type": "publicKey" + }, + { + "name": "feeRecipient", + "type": "publicKey" + }, + { + "name": "solPrice", + "type": "u64" + } + ] + } + }, + { + "name": "registeredChain", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "maxGasDropoff", + "type": "u64" + }, + { + "name": "basePrice", + "type": "u64" + }, + { + "name": "nativePrice", + "type": "u64" + }, + { + "name": "gasPrice", + "type": "u64" + } + ] + } + }, + { + "name": "registeredNtt", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "wormholeTransceiverIndex", + "type": "u8" + }, + { + "name": "gasCost", + "type": "u32" + } + ] + } + }, + { + "name": "relayRequest", + "type": { + "kind": "struct", + "fields": [ + { + "name": "requestedGasDropoff", + "type": "u64" + } + ] + } + } + ], + "types": [ + { + "name": "RegisterChainArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "RegisterNttArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nttProgramId", + "type": "publicKey" + }, + { + "name": "wormholeTransceiverIndex", + "type": "u8" + }, + { + "name": "gasCost", + "type": "u32" + } + ] + } + }, + { + "name": "DeregisterNttArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nttProgramId", + "type": "publicKey" + } + ] + } + }, + { + "name": "RequestRelayArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "gasDropoff", + "type": "u64" + }, + { + "name": "maxFee", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateSolPriceArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "solPrice", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateChainPricesArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nativePrice", + "type": "u64" + }, + { + "name": "gasPrice", + "type": "u64" + } + ] + } + }, + { + "name": "UpdateChainParamsArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "maxGasDropoff", + "type": "u64" + }, + { + "name": "basePrice", + "type": "u64" + } + ] + } + } + ], + "errors": [ + { + "code": 6001, + "name": "ExceedsUserMaxFee", + "msg": "Relay fees exceeds specified max" + }, + { + "code": 6002, + "name": "ExceedsMaxGasDropoff", + "msg": "Requested gas dropoff exceeds max allowed for chain" + }, + { + "code": 6003, + "name": "InvalidFeeRecipient", + "msg": "The specified fee recipient does not match the address in the instance accound" + }, + { + "code": 6004, + "name": "RelayingToChainDisabled", + "msg": "Relaying to the specified chain is disabled" + }, + { + "code": 6005, + "name": "OutboxItemNotReleased", + "msg": "Relaying to the specified chain is disabled" + }, + { + "code": 6006, + "name": "ScalingOverflow", + "msg": "Scaled value exceeds u64::MAX" + }, + { + "code": 6007, + "name": "DivByZero", + "msg": "Cannot divide by zero" + }, + { + "code": 6257, + "name": "FeeRecipientCannotBeDefault", + "msg": "The fee recipient cannot be the default address (0x0)" + }, + { + "code": 6258, + "name": "NotAuthorized", + "msg": "Must be owner or assistant" + }, + { + "code": 6259, + "name": "PriceCannotBeZero", + "msg": "The price cannot be zero" + } + ] +} + diff --git a/solana/ts/idl/3_0_0/ts/ntt_transceiver.ts b/solana/ts/idl/3_0_0/ts/ntt_transceiver.ts new file mode 100644 index 000000000..45fedee4f --- /dev/null +++ b/solana/ts/idl/3_0_0/ts/ntt_transceiver.ts @@ -0,0 +1,1397 @@ +export type NttTransceiver = { + "version": "3.0.0", + "name": "ntt_transceiver", + "instructions": [ + { + "name": "transceiverType", + "accounts": [], + "args": [], + "returns": "string" + }, + { + "name": "setWormholePeer", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetTransceiverPeerArgs" + } + } + ] + }, + { + "name": "receiveWormholeMessage", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "releaseWormholeOutbound", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "manager", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItemSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseOutboundArgs" + } + } + ] + }, + { + "name": "broadcastWormholeId", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "broadcastWormholePeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "BroadcastPeerArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "config", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "owner", + "docs": [ + "Owner of the program." + ], + "type": "publicKey" + }, + { + "name": "pendingOwner", + "docs": [ + "Pending next owner (before claiming ownership)." + ], + "type": { + "option": "publicKey" + } + }, + { + "name": "mint", + "docs": [ + "Mint address of the token managed by this program." + ], + "type": "publicKey" + }, + { + "name": "tokenProgram", + "docs": [ + "Address of the token program (token or token22). This could always be queried", + "from the [`mint`] account's owner, but storing it here avoids an indirection", + "on the client side." + ], + "type": "publicKey" + }, + { + "name": "mode", + "docs": [ + "The mode that this program is running in. This is used to determine", + "whether the program is burning tokens or locking tokens." + ], + "type": { + "defined": "Mode" + } + }, + { + "name": "chainId", + "docs": [ + "The chain id of the chain that this program is running on. We don't", + "hardcode this so that the program is deployable on any potential SVM", + "forks." + ], + "type": { + "defined": "ChainId" + } + }, + { + "name": "nextTransceiverId", + "docs": [ + "The next transceiver id to use when registering an transceiver." + ], + "type": "u8" + }, + { + "name": "threshold", + "docs": [ + "The number of transceivers that must attest to a transfer before it is", + "accepted." + ], + "type": "u8" + }, + { + "name": "enabledTransceivers", + "docs": [ + "Bitmap of enabled transceivers.", + "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + ], + "type": { + "defined": "Bitmap" + } + }, + { + "name": "paused", + "docs": [ + "Pause the program. This is useful for upgrades and other maintenance." + ], + "type": "bool" + }, + { + "name": "custody", + "docs": [ + "The custody account that holds tokens in locking mode." + ], + "type": "publicKey" + } + ] + } + }, + { + "name": "outboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "TrimmedAmount" + } + }, + { + "name": "sender", + "type": "publicKey" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientNttManager", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "releaseTimestamp", + "type": "i64" + }, + { + "name": "released", + "type": { + "defined": "Bitmap" + } + } + ] + } + }, + { + "name": "registeredTransceiver", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "id", + "type": "u8" + }, + { + "name": "transceiverAddress", + "type": "publicKey" + } + ] + } + }, + { + "name": "transceiverPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "bridgeData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetIndex", + "docs": [ + "The current guardian set index, used to decide which signature sets to accept." + ], + "type": "u32" + }, + { + "name": "lastLamports", + "docs": [ + "Lamports in the collection account" + ], + "type": "u64" + }, + { + "name": "config", + "docs": [ + "Bridge configuration, which is set once upon initialization." + ], + "type": { + "defined": "BridgeConfig" + } + } + ] + } + } + ], + "types": [ + { + "name": "Bitmap", + "type": { + "kind": "struct", + "fields": [ + { + "name": "map", + "type": "u128" + } + ] + } + }, + { + "name": "ChainId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u16" + } + ] + } + }, + { + "name": "Mode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Locking" + }, + { + "name": "Burning" + } + ] + } + }, + { + "name": "TrimmedAmount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + }, + { + "name": "SetTransceiverPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BroadcastPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "ReleaseOutboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "BridgeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetExpirationTime", + "docs": [ + "Period for how long a guardian set is valid after it has been replaced by a new one. This", + "guarantees that VAAs issued by that set can still be submitted for a certain period. In", + "this period we still trust the old guardian set." + ], + "type": "u32" + }, + { + "name": "fee", + "docs": [ + "Amount of lamports that needs to be paid to the protocol to post a message" + ], + "type": "u64" + } + ] + } + } + ] +} +export const IDL: NttTransceiver = { + "version": "3.0.0", + "name": "ntt_transceiver", + "instructions": [ + { + "name": "transceiverType", + "accounts": [], + "args": [], + "returns": "string" + }, + { + "name": "setWormholePeer", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "owner", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "peer", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "SetTransceiverPeerArgs" + } + } + ] + }, + { + "name": "receiveWormholeMessage", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "transceiverMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "releaseWormholeOutbound", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "accounts": [ + { + "name": "config", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "outboxItem", + "isMut": true, + "isSigner": false + }, + { + "name": "transceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": false + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + }, + { + "name": "manager", + "isMut": false, + "isSigner": false + }, + { + "name": "outboxItemSigner", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "ReleaseOutboundArgs" + } + } + ] + }, + { + "name": "broadcastWormholeId", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "mint", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [] + }, + { + "name": "broadcastWormholePeer", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "config", + "isMut": false, + "isSigner": false + }, + { + "name": "peer", + "isMut": false, + "isSigner": false + }, + { + "name": "wormholeMessage", + "isMut": true, + "isSigner": true + }, + { + "name": "emitter", + "isMut": false, + "isSigner": false + }, + { + "name": "wormhole", + "accounts": [ + { + "name": "bridge", + "isMut": true, + "isSigner": false + }, + { + "name": "feeCollector", + "isMut": true, + "isSigner": false + }, + { + "name": "sequence", + "isMut": true, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "clock", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ] + } + ], + "args": [ + { + "name": "args", + "type": { + "defined": "BroadcastPeerArgs" + } + } + ] + } + ], + "accounts": [ + { + "name": "config", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "owner", + "docs": [ + "Owner of the program." + ], + "type": "publicKey" + }, + { + "name": "pendingOwner", + "docs": [ + "Pending next owner (before claiming ownership)." + ], + "type": { + "option": "publicKey" + } + }, + { + "name": "mint", + "docs": [ + "Mint address of the token managed by this program." + ], + "type": "publicKey" + }, + { + "name": "tokenProgram", + "docs": [ + "Address of the token program (token or token22). This could always be queried", + "from the [`mint`] account's owner, but storing it here avoids an indirection", + "on the client side." + ], + "type": "publicKey" + }, + { + "name": "mode", + "docs": [ + "The mode that this program is running in. This is used to determine", + "whether the program is burning tokens or locking tokens." + ], + "type": { + "defined": "Mode" + } + }, + { + "name": "chainId", + "docs": [ + "The chain id of the chain that this program is running on. We don't", + "hardcode this so that the program is deployable on any potential SVM", + "forks." + ], + "type": { + "defined": "ChainId" + } + }, + { + "name": "nextTransceiverId", + "docs": [ + "The next transceiver id to use when registering an transceiver." + ], + "type": "u8" + }, + { + "name": "threshold", + "docs": [ + "The number of transceivers that must attest to a transfer before it is", + "accepted." + ], + "type": "u8" + }, + { + "name": "enabledTransceivers", + "docs": [ + "Bitmap of enabled transceivers.", + "The maximum number of transceivers is equal to [`Bitmap::BITS`]." + ], + "type": { + "defined": "Bitmap" + } + }, + { + "name": "paused", + "docs": [ + "Pause the program. This is useful for upgrades and other maintenance." + ], + "type": "bool" + }, + { + "name": "custody", + "docs": [ + "The custody account that holds tokens in locking mode." + ], + "type": "publicKey" + } + ] + } + }, + { + "name": "outboxItem", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": { + "defined": "TrimmedAmount" + } + }, + { + "name": "sender", + "type": "publicKey" + }, + { + "name": "recipientChain", + "type": { + "defined": "ChainId" + } + }, + { + "name": "recipientNttManager", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "recipientAddress", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "releaseTimestamp", + "type": "i64" + }, + { + "name": "released", + "type": { + "defined": "Bitmap" + } + } + ] + } + }, + { + "name": "registeredTransceiver", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "id", + "type": "u8" + }, + { + "name": "transceiverAddress", + "type": "publicKey" + } + ] + } + }, + { + "name": "transceiverPeer", + "docs": [ + "A peer on another chain. Stored in a PDA seeded by the chain id." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "bridgeData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetIndex", + "docs": [ + "The current guardian set index, used to decide which signature sets to accept." + ], + "type": "u32" + }, + { + "name": "lastLamports", + "docs": [ + "Lamports in the collection account" + ], + "type": "u64" + }, + { + "name": "config", + "docs": [ + "Bridge configuration, which is set once upon initialization." + ], + "type": { + "defined": "BridgeConfig" + } + } + ] + } + } + ], + "types": [ + { + "name": "Bitmap", + "type": { + "kind": "struct", + "fields": [ + { + "name": "map", + "type": "u128" + } + ] + } + }, + { + "name": "ChainId", + "type": { + "kind": "struct", + "fields": [ + { + "name": "id", + "type": "u16" + } + ] + } + }, + { + "name": "Mode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Locking" + }, + { + "name": "Burning" + } + ] + } + }, + { + "name": "TrimmedAmount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "decimals", + "type": "u8" + } + ] + } + }, + { + "name": "SetTransceiverPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": { + "defined": "ChainId" + } + }, + { + "name": "address", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "BroadcastPeerArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "chainId", + "type": "u16" + } + ] + } + }, + { + "name": "ReleaseOutboundArgs", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revertOnDelay", + "type": "bool" + } + ] + } + }, + { + "name": "BridgeConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "guardianSetExpirationTime", + "docs": [ + "Period for how long a guardian set is valid after it has been replaced by a new one. This", + "guarantees that VAAs issued by that set can still be submitted for a certain period. In", + "this period we still trust the old guardian set." + ], + "type": "u32" + }, + { + "name": "fee", + "docs": [ + "Amount of lamports that needs to be paid to the protocol to post a message" + ], + "type": "u64" + } + ] + } + } + ] +} + diff --git a/solana/ts/idl/3_0_0/ts/wormhole_governance.ts b/solana/ts/idl/3_0_0/ts/wormhole_governance.ts new file mode 100644 index 000000000..13289f7b7 --- /dev/null +++ b/solana/ts/idl/3_0_0/ts/wormhole_governance.ts @@ -0,0 +1,153 @@ +export type WormholeGovernance = { + "version": "3.0.0", + "name": "wormhole_governance", + "instructions": [ + { + "name": "governance", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "governance", + "isMut": true, + "isSigner": false, + "docs": [ + "governed program. This account is validated by Wormhole, not this program." + ] + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "replay", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "replayProtection", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "InvalidGovernanceChain", + "msg": "InvalidGovernanceChain" + }, + { + "code": 6001, + "name": "InvalidGovernanceEmitter", + "msg": "InvalidGovernanceEmitter" + }, + { + "code": 6002, + "name": "InvalidGovernanceProgram", + "msg": "InvalidGovernanceProgram" + } + ] +} +export const IDL: WormholeGovernance = { + "version": "3.0.0", + "name": "wormhole_governance", + "instructions": [ + { + "name": "governance", + "accounts": [ + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "governance", + "isMut": true, + "isSigner": false, + "docs": [ + "governed program. This account is validated by Wormhole, not this program." + ] + }, + { + "name": "vaa", + "isMut": false, + "isSigner": false + }, + { + "name": "program", + "isMut": false, + "isSigner": false + }, + { + "name": "replay", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "replayProtection", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "type": "u8" + } + ] + } + } + ], + "errors": [ + { + "code": 6000, + "name": "InvalidGovernanceChain", + "msg": "InvalidGovernanceChain" + }, + { + "code": 6001, + "name": "InvalidGovernanceEmitter", + "msg": "InvalidGovernanceEmitter" + }, + { + "code": 6002, + "name": "InvalidGovernanceProgram", + "msg": "InvalidGovernanceProgram" + } + ] +} + diff --git a/solana/ts/lib/anchor-idl/1_0_0.ts b/solana/ts/lib/anchor-idl/1_0_0.ts index bca149d6e..9c313531b 100644 --- a/solana/ts/lib/anchor-idl/1_0_0.ts +++ b/solana/ts/lib/anchor-idl/1_0_0.ts @@ -6,7 +6,7 @@ import { type WormholeGovernance } from "../../idl/1_0_0/ts/wormhole_governance. import { IDL as governance } from "../../idl/1_0_0/ts/wormhole_governance.js"; export namespace _1_0_0 { - export const idl = { ntt, quoter, governance }; + export const idl = { ntt, transceiver: ntt, quoter, governance }; export type RawExampleNativeTokenTransfers = ExampleNativeTokenTransfers; export type RawNttQuoter = NttQuoter; export type RawWormholeGovernance = WormholeGovernance; diff --git a/solana/ts/lib/anchor-idl/2_0_0.ts b/solana/ts/lib/anchor-idl/2_0_0.ts index 1b98d0f92..5e0e78fc2 100644 --- a/solana/ts/lib/anchor-idl/2_0_0.ts +++ b/solana/ts/lib/anchor-idl/2_0_0.ts @@ -6,7 +6,7 @@ import { type WormholeGovernance } from "../../idl/2_0_0/ts/wormhole_governance. import { IDL as governance } from "../../idl/2_0_0/ts/wormhole_governance.js"; export namespace _2_0_0 { - export const idl = { ntt, quoter, governance }; + export const idl = { ntt, transceiver: ntt, quoter, governance }; export type RawExampleNativeTokenTransfers = ExampleNativeTokenTransfers; export type RawNttQuoter = NttQuoter; export type RawWormholeGovernance = WormholeGovernance; diff --git a/solana/ts/lib/anchor-idl/3_0_0.ts b/solana/ts/lib/anchor-idl/3_0_0.ts new file mode 100644 index 000000000..ca55ddd17 --- /dev/null +++ b/solana/ts/lib/anchor-idl/3_0_0.ts @@ -0,0 +1,16 @@ +import { type ExampleNativeTokenTransfers } from "../../idl/3_0_0/ts/example_native_token_transfers.js"; +import { IDL as ntt } from "../../idl/3_0_0/ts/example_native_token_transfers.js"; +import { type NttTransceiver } from "../../idl/3_0_0/ts/ntt_transceiver.js"; +import { IDL as transceiver } from "../../idl/3_0_0/ts/ntt_transceiver.js"; +import { type NttQuoter } from "../../idl/3_0_0/ts/ntt_quoter.js"; +import { IDL as quoter } from "../../idl/3_0_0/ts/ntt_quoter.js"; +import { type WormholeGovernance } from "../../idl/3_0_0/ts/wormhole_governance.js"; +import { IDL as governance } from "../../idl/3_0_0/ts/wormhole_governance.js"; + +export namespace _3_0_0 { + export const idl = { ntt, transceiver, quoter, governance }; + export type RawExampleNativeTokenTransfers = ExampleNativeTokenTransfers; + export type RawNttTransceiver = NttTransceiver; + export type RawNttQuoter = NttQuoter; + export type RawWormholeGovernance = WormholeGovernance; +} diff --git a/solana/ts/lib/anchor-idl/index.ts b/solana/ts/lib/anchor-idl/index.ts index 9c472b912..6ad25e2d3 100644 --- a/solana/ts/lib/anchor-idl/index.ts +++ b/solana/ts/lib/anchor-idl/index.ts @@ -1,2 +1,3 @@ export * from "./1_0_0.js"; export * from "./2_0_0.js"; +export * from "./3_0_0.js"; diff --git a/solana/ts/lib/bindings.ts b/solana/ts/lib/bindings.ts index cf2dd43d0..d60bc735e 100644 --- a/solana/ts/lib/bindings.ts +++ b/solana/ts/lib/bindings.ts @@ -1,11 +1,12 @@ import { IdlAccounts, Program } from "@coral-xyz/anchor"; import { Connection } from "@solana/web3.js"; -import { _1_0_0, _2_0_0 } from "./anchor-idl/index.js"; +import { _1_0_0, _2_0_0, _3_0_0 } from "./anchor-idl/index.js"; import { Ntt } from "@wormhole-foundation/sdk-definitions-ntt"; export interface IdlBinding { idl: { ntt: NttBindings.NativeTokenTransfer; + transceiver: NttBindings.Transceiver; quoter: NttBindings.Quoter; }; } @@ -14,6 +15,7 @@ export interface IdlBinding { // We check for the first match in descending order, allowing for higher minor and patch versions // being used by the live contract (these are supposed to still be compatible with older ABIs). export const IdlVersions = [ + ["3.0.0", _3_0_0], ["2.0.0", _2_0_0], ["1.0.0", _1_0_0], ] as const; @@ -23,11 +25,21 @@ export type IdlVersion = (typeof IdlVersions)[number][0]; export namespace NttBindings { export type NativeTokenTransfer = V extends "1.0.0" ? _1_0_0.RawExampleNativeTokenTransfers - : _2_0_0.RawExampleNativeTokenTransfers; + : V extends "2.0.0" + ? _2_0_0.RawExampleNativeTokenTransfers + : _3_0_0.RawExampleNativeTokenTransfers; export type Quoter = V extends "1.0.0" ? _1_0_0.RawNttQuoter - : _2_0_0.RawNttQuoter; + : V extends "2.0.0" + ? _2_0_0.RawNttQuoter + : _3_0_0.RawNttQuoter; + + export type Transceiver = V extends "1.0.0" + ? _1_0_0.RawExampleNativeTokenTransfers + : V extends "2.0.0" + ? _2_0_0.RawExampleNativeTokenTransfers + : _3_0_0.RawNttTransceiver; type ProgramAccounts = IdlAccounts< NttBindings.NativeTokenTransfer @@ -59,6 +71,19 @@ export function getNttProgram( }); } +export function getTransceiverProgram( + connection: Connection, + address: string, + version: V +) { + const { + idl: { transceiver }, + } = loadIdlVersion(version); + return new Program>(transceiver, address, { + connection, + }); +} + export function getQuoterProgram( connection: Connection, address: string, diff --git a/solana/ts/lib/ntt.ts b/solana/ts/lib/ntt.ts index 5384ef025..c3507c1c4 100644 --- a/solana/ts/lib/ntt.ts +++ b/solana/ts/lib/ntt.ts @@ -12,11 +12,9 @@ import { AddressLookupTableProgram, Commitment, Connection, - Keypair, PublicKey, PublicKeyInitData, SystemProgram, - Transaction, TransactionInstruction, TransactionMessage, VersionedTransaction, @@ -39,7 +37,6 @@ import { import { Ntt } from "@wormhole-foundation/sdk-definitions-ntt"; import { getAssociatedTokenAddressSync } from "@solana/spl-token"; -import { SolanaTransaction } from "@wormhole-foundation/sdk-solana"; import { utils } from "@wormhole-foundation/sdk-solana-core"; import { IdlVersion, @@ -86,7 +83,6 @@ export namespace NTT { /** pdas returns an object containing all functions to compute program addresses */ export const pdas = (programId: PublicKeyInitData) => { const configAccount = (): PublicKey => derivePda("config", programId); - const emitterAccount = (): PublicKey => derivePda("emitter", programId); const inboxRateLimitAccount = (chain: Chain): PublicKey => derivePda(["inbox_rate_limit", chainToBytes(chain)], programId); const inboxItemAccount = ( @@ -103,17 +99,8 @@ export namespace NTT { derivePda("token_authority", programId); const peerAccount = (chain: Chain): PublicKey => derivePda(["peer", chainToBytes(chain)], programId); - const transceiverPeerAccount = (chain: Chain): PublicKey => - derivePda(["transceiver_peer", chainToBytes(chain)], programId); const registeredTransceiver = (transceiver: PublicKey): PublicKey => derivePda(["registered_transceiver", transceiver.toBytes()], programId); - const transceiverMessageAccount = ( - chain: Chain, - id: Uint8Array - ): PublicKey => - derivePda(["transceiver_message", chainToBytes(chain), id], programId); - const wormholeMessageAccount = (outboxItem: PublicKey): PublicKey => - derivePda(["message", outboxItem.toBytes()], programId); const lutAccount = (): PublicKey => derivePda("lut", programId); const lutAuthority = (): PublicKey => derivePda("lut_authority", programId); const sessionAuthority = ( @@ -144,17 +131,39 @@ export namespace NTT { inboxItemAccount, sessionAuthority, tokenAuthority, - emitterAccount, - wormholeMessageAccount, peerAccount, - transceiverPeerAccount, - transceiverMessageAccount, registeredTransceiver, lutAccount, lutAuthority, }; }; + /** Type of object containing methods to compute program addresses */ + export type TransceiverPdas = ReturnType; + /** pdas returns an object containing all functions to compute program addresses */ + export const transceiverPdas = (programId: PublicKeyInitData) => { + const emitterAccount = (): PublicKey => derivePda("emitter", programId); + const outboxItemSigner = () => derivePda(["outbox_item_signer"], programId); + const transceiverPeerAccount = (chain: Chain): PublicKey => + derivePda(["transceiver_peer", chainToBytes(chain)], programId); + const transceiverMessageAccount = ( + chain: Chain, + id: Uint8Array + ): PublicKey => + derivePda(["transceiver_message", chainToBytes(chain), id], programId); + const wormholeMessageAccount = (outboxItem: PublicKey): PublicKey => + derivePda(["message", outboxItem.toBytes()], programId); + + // TODO: memoize? + return { + emitterAccount, + outboxItemSigner, + transceiverPeerAccount, + transceiverMessageAccount, + wormholeMessageAccount, + }; + }; + export async function getVersion( connection: Connection, programId: PublicKey, @@ -270,6 +279,7 @@ export namespace NTT { export async function initializeOrUpdateLUT( program: Program>, config: NttBindings.Config, + whTransceiver: PublicKey, args: { payer: PublicKey; wormholeId: PublicKey; @@ -292,10 +302,11 @@ export namespace NTT { }); const whAccs = utils.getWormholeDerivedAccounts( - program.programId, + whTransceiver, args.wormholeId.toString() ); + // TODO: add `whAccs.emitter`, `whTransceiver`, and transceiverEmitter PDA account to LUT const entries = { config: pdas.configAccount(), custody: config.custody, @@ -518,47 +529,6 @@ export namespace NTT { return transferIx; } - /** - * Creates a release_outbound instruction. The `payer` needs to sign the transaction. - */ - export async function createReleaseOutboundInstruction( - program: Program>, - args: { - wormholeId: PublicKey; - payer: PublicKey; - outboxItem: PublicKey; - revertOnDelay: boolean; - }, - pdas?: Pdas - ): Promise { - pdas = pdas ?? NTT.pdas(program.programId); - - const whAccs = utils.getWormholeDerivedAccounts( - program.programId, - args.wormholeId - ); - - return await program.methods - .releaseWormholeOutbound({ - revertOnDelay: args.revertOnDelay, - }) - .accounts({ - payer: args.payer, - config: { config: pdas.configAccount() }, - outboxItem: args.outboxItem, - wormholeMessage: pdas.wormholeMessageAccount(args.outboxItem), - emitter: whAccs.wormholeEmitter, - transceiver: pdas.registeredTransceiver(program.programId), - wormhole: { - bridge: whAccs.wormholeBridge, - feeCollector: whAccs.wormholeFeeCollector, - sequence: whAccs.wormholeSequence, - program: args.wormholeId, - }, - }) - .instruction(); - } - // TODO: document that if recipient is provided, then the instruction can be // created before the inbox item is created (i.e. they can be put in the same tx) export async function createReleaseInboundMintInstruction( @@ -789,118 +759,6 @@ export namespace NTT { .instruction(); } - export async function setWormholeTransceiverPeer( - program: Program>, - args: { - wormholeId: PublicKey; - payer: PublicKey; - owner: PublicKey; - chain: Chain; - address: ArrayLike; - }, - pdas?: Pdas - ) { - pdas = pdas ?? NTT.pdas(program.programId); - const ix = await program.methods - .setWormholePeer({ - chainId: { id: toChainId(args.chain) }, - address: Array.from(args.address), - }) - .accounts({ - payer: args.payer, - owner: args.owner, - config: pdas.configAccount(), - peer: pdas.transceiverPeerAccount(args.chain), - }) - .instruction(); - - const wormholeMessage = Keypair.generate(); - const whAccs = utils.getWormholeDerivedAccounts( - program.programId, - args.wormholeId - ); - - const broadcastIx = await program.methods - .broadcastWormholePeer({ chainId: toChainId(args.chain) }) - .accounts({ - payer: args.payer, - config: pdas.configAccount(), - peer: pdas.transceiverPeerAccount(args.chain), - wormholeMessage: wormholeMessage.publicKey, - emitter: pdas.emitterAccount(), - wormhole: { - bridge: whAccs.wormholeBridge, - feeCollector: whAccs.wormholeFeeCollector, - sequence: whAccs.wormholeSequence, - program: args.wormholeId, - }, - }) - .instruction(); - - const transaction = new Transaction().add(ix, broadcastIx); - transaction.feePayer = args.payer; - return { - transaction, - signers: [wormholeMessage], - } as SolanaTransaction; - } - - export async function registerTransceiver( - program: Program>, - config: NttBindings.Config, - args: { - wormholeId: PublicKey; - payer: PublicKey; - owner: PublicKey; - transceiver: PublicKey; - }, - pdas?: Pdas - ) { - pdas = pdas ?? NTT.pdas(program.programId); - const ix = await program.methods - .registerTransceiver() - .accounts({ - payer: args.payer, - owner: args.owner, - config: pdas.configAccount(), - transceiver: args.transceiver, - registeredTransceiver: pdas.registeredTransceiver(args.transceiver), - }) - .instruction(); - - const wormholeMessage = Keypair.generate(); - const whAccs = utils.getWormholeDerivedAccounts( - program.programId, - args.wormholeId - ); - const broadcastIx = await program.methods - .broadcastWormholeId() - .accountsStrict({ - payer: args.payer, - config: pdas.configAccount(), - mint: config.mint, - wormholeMessage: wormholeMessage.publicKey, - emitter: pdas.emitterAccount(), - wormhole: { - bridge: whAccs.wormholeBridge, - feeCollector: whAccs.wormholeFeeCollector, - sequence: whAccs.wormholeSequence, - program: args.wormholeId, - systemProgram: SystemProgram.programId, - clock: web3.SYSVAR_CLOCK_PUBKEY, - rent: web3.SYSVAR_RENT_PUBKEY, - }, - }) - .instruction(); - - const transaction = new Transaction().add(ix, broadcastIx); - transaction.feePayer = args.payer; - return { - transaction, - signers: [wormholeMessage], - }; - } - export async function createSetOutboundLimitInstruction( program: Program>, args: { @@ -945,66 +803,36 @@ export namespace NTT { .instruction(); } - export async function createReceiveWormholeMessageInstruction( - program: Program>, - args: { - wormholeId: PublicKey; - payer: PublicKey; - vaa: VAA<"Ntt:WormholeTransfer">; - }, - pdas?: Pdas - ): Promise { - pdas = pdas ?? NTT.pdas(program.programId); - - const wormholeNTT = args.vaa; - const nttMessage = wormholeNTT.payload.nttManagerPayload; - const chain = wormholeNTT.emitterChain; - - const transceiverPeer = pdas.transceiverPeerAccount(chain); - - return await program.methods - .receiveWormholeMessage() - .accounts({ - payer: args.payer, - config: { config: pdas.configAccount() }, - peer: transceiverPeer, - vaa: utils.derivePostedVaaKey( - args.wormholeId, - Buffer.from(wormholeNTT.hash) - ), - transceiverMessage: pdas.transceiverMessageAccount( - chain, - nttMessage.id - ), - }) - .instruction(); - } export async function createRedeemInstruction( program: Program>, config: NttBindings.Config, + transceiverProgramId: PublicKey, args: { payer: PublicKey; vaa: VAA<"Ntt:WormholeTransfer">; }, - pdas?: Pdas + pdas?: Pdas, + transceiverPdas?: TransceiverPdas ): Promise { pdas = pdas ?? NTT.pdas(program.programId); + transceiverPdas = + transceiverPdas ?? NTT.transceiverPdas(transceiverProgramId); const wormholeNTT = args.vaa; const nttMessage = wormholeNTT.payload.nttManagerPayload; const chain = wormholeNTT.emitterChain; - return await program.methods + return program.methods .redeem({}) .accounts({ payer: args.payer, config: pdas.configAccount(), peer: pdas.peerAccount(chain), - transceiverMessage: pdas.transceiverMessageAccount( + transceiverMessage: transceiverPdas.transceiverMessageAccount( chain, nttMessage.id ), - transceiver: pdas.registeredTransceiver(program.programId), + transceiver: pdas.registeredTransceiver(transceiverProgramId), mint: config.mint, inboxItem: pdas.inboxItemAccount(chain, nttMessage), inboxRateLimit: pdas.inboxRateLimitAccount(chain), diff --git a/solana/ts/sdk/ntt.ts b/solana/ts/sdk/ntt.ts index 3e87b81f2..3e8982d2b 100644 --- a/solana/ts/sdk/ntt.ts +++ b/solana/ts/sdk/ntt.ts @@ -13,7 +13,7 @@ import { VersionedTransaction, } from "@solana/web3.js"; -import { Chain, Network } from "@wormhole-foundation/sdk-base"; +import { Chain, Network, toChainId } from "@wormhole-foundation/sdk-base"; import { AccountAddress, ChainAddress, @@ -25,7 +25,7 @@ import { } from "@wormhole-foundation/sdk-definitions"; import { Ntt, - NttTransceiver, + SolanaNttTransceiver, WormholeNttTransceiver, } from "@wormhole-foundation/sdk-definitions-ntt"; import { @@ -42,16 +42,33 @@ import { utils, } from "@wormhole-foundation/sdk-solana-core"; import BN from "bn.js"; +import { + IdlVersion, + NttBindings, + getNttProgram, + getTransceiverProgram, +} from "../lib/bindings.js"; import { NTT, NttQuoter, WEI_PER_GWEI } from "../lib/index.js"; - -import { IdlVersion, NttBindings, getNttProgram } from "../lib/bindings.js"; +import { parseVersion } from "../lib/utils.js"; export class SolanaNttWormholeTransceiver< N extends Network, C extends SolanaChains -> implements NttTransceiver +> implements + WormholeNttTransceiver, + SolanaNttTransceiver { - constructor(readonly manager: SolanaNtt, readonly address: PublicKey) {} + programId: PublicKey; + pdas: NTT.TransceiverPdas; + + constructor( + readonly manager: SolanaNtt, + readonly program: Program>, + readonly version: string = "3.0.0" + ) { + this.programId = program.programId; + this.pdas = NTT.transceiverPdas(program.programId); + } async getPauser(): Promise | null> { return null; @@ -61,29 +78,145 @@ export class SolanaNttWormholeTransceiver< throw new Error("Method not implemented."); } - async *receive(_attestation: WormholeNttTransceiver.VAA) { - // TODO: this is implemented below (in the transceiver code). it could get - // tricky in general with multiple transceivers, as they might return an - // instruction, or multiple instructions, etc. - // in any case, we should implement this here. - throw new Error("Method not implemented."); + // NOTE: this method is not used for the Solana Wormhole transceiver. + // `createReceiveIx` is used directly as it can be batched with other ixs in a single tx + async *receive( + attestation: WormholeNttTransceiver.VAA, + payer: AccountAddress + ) { + if (attestation.payloadName !== "WormholeTransfer") { + throw new Error("Invalid attestation payload"); + } + const senderAddress = new SolanaAddress(payer).unwrap(); + + const ix = await this.createReceiveIx(attestation, senderAddress); + const tx = new Transaction(); + tx.feePayer = senderAddress; + tx.add(ix); + yield this.manager.createUnsignedTx({ transaction: tx }, "Ntt.Redeem"); + } + + async createReceiveIx( + attestation: WormholeNttTransceiver.VAA<"WormholeTransfer">, + payer: PublicKey + ) { + const nttMessage = attestation.payload.nttManagerPayload; + const chain = attestation.emitterChain; + return this.program.methods + .receiveWormholeMessage() + .accounts({ + payer, + config: { config: this.manager.pdas.configAccount() }, + peer: this.pdas.transceiverPeerAccount(chain), + vaa: utils.derivePostedVaaKey( + this.manager.core.address, + Buffer.from(attestation.hash) + ), + transceiverMessage: this.pdas.transceiverMessageAccount( + chain, + nttMessage.id + ), + }) + .instruction(); + } + + async getTransceiverType(payer: AccountAddress): Promise { + // NOTE: transceiver type does not exist for versions < 3.x.x so we hardcode + const [major, , ,] = parseVersion(this.version); + if (major < 3) { + return "wormhole"; + } + + // the anchor library has a built-in method to read view functions. However, + // it requires a signer, which would trigger a wallet prompt on the frontend. + // Instead, we manually construct a versioned transaction and call the + // simulate function with sigVerify: false below. + // + // This way, the simulation won't require a signer, but it still requires + // the pubkey of an account that has some lamports in it (since the + // simulation checks if the account has enough money to pay for the transaction). + // + // It's a little unfortunate but it's the best we can do. + const payerKey = new SolanaAddress(payer).unwrap(); + const ix = await this.program.methods + .transceiverType() + .accountsStrict({}) + .instruction(); + const latestBlockHash = + await this.program.provider.connection.getLatestBlockhash(); + + const msg = new TransactionMessage({ + payerKey, + recentBlockhash: latestBlockHash.blockhash, + instructions: [ix], + }).compileToV0Message(); + + const tx = new VersionedTransaction(msg); + + const txSimulation = + await this.program.provider.connection.simulateTransaction(tx, { + sigVerify: false, + }); + + // the return buffer is in base64 and it encodes the string with a 32 bit + // little endian length prefix. + if (txSimulation.value.returnData?.data[0]) { + const buffer = Buffer.from( + txSimulation.value.returnData?.data[0], + "base64" + ); + const len = buffer.readUInt32LE(0); + return buffer.subarray(4, len + 4).toString(); + } else { + throw new Error("no transceiver type found"); + } } getAddress(): ChainAddress { return { chain: this.manager.chain, - address: toUniversal(this.manager.chain, this.address.toBase58()), + address: toUniversal( + this.manager.chain, + this.pdas.emitterAccount().toBase58() + ), }; } async *setPeer(peer: ChainAddress, payer: AccountAddress) { - yield* this.manager.setWormholeTransceiverPeer(peer, payer); + const sender = new SolanaAddress(payer).unwrap(); + const ix = await this.program.methods + .setWormholePeer({ + chainId: { id: toChainId(peer.chain) }, + address: Array.from(peer.address.toUniversalAddress().toUint8Array()), + }) + .accounts({ + payer: sender, + owner: sender, + config: this.manager.pdas.configAccount(), + peer: this.pdas.transceiverPeerAccount(peer.chain), + }) + .instruction(); + + const wormholeMessage = Keypair.generate(); + const broadcastIx = await this.createBroadcastWormholePeerIx( + peer.chain, + sender, + wormholeMessage.publicKey + ); + + const tx = new Transaction(); + tx.feePayer = sender; + tx.add(ix, broadcastIx); + yield this.manager.createUnsignedTx( + { transaction: tx, signers: [wormholeMessage] }, + "Ntt.SetWormholeTransceiverPeer" + ); } async getPeer(chain: C): Promise | null> { const peer = await this.manager.program.account.transceiverPeer.fetchNullable( - this.manager.pdas.transceiverPeerAccount(chain) + this.pdas.transceiverPeerAccount(chain) ); if (!peer) return null; @@ -93,6 +226,105 @@ export class SolanaNttWormholeTransceiver< address: toUniversal(chain, new Uint8Array(peer.address)), }; } + + async createBroadcastWormholeIdIx( + payer: PublicKey, + config: NttBindings.Config, + wormholeMessage: PublicKey + ): Promise { + const whAccs = utils.getWormholeDerivedAccounts( + this.program.programId, + this.manager.core.address + ); + + return this.program.methods + .broadcastWormholeId() + .accountsStrict({ + payer, + config: this.manager.pdas.configAccount(), + mint: config.mint, + wormholeMessage: wormholeMessage, + emitter: whAccs.wormholeEmitter, + wormhole: { + bridge: whAccs.wormholeBridge, + feeCollector: whAccs.wormholeFeeCollector, + sequence: whAccs.wormholeSequence, + program: this.manager.core.address, + systemProgram: SystemProgram.programId, + clock: web3.SYSVAR_CLOCK_PUBKEY, + rent: web3.SYSVAR_RENT_PUBKEY, + }, + }) + .instruction(); + } + + async createBroadcastWormholePeerIx( + chain: Chain, + payer: PublicKey, + wormholeMessage: PublicKey + ): Promise { + const whAccs = utils.getWormholeDerivedAccounts( + this.program.programId, + this.manager.core.address + ); + + return this.program.methods + .broadcastWormholePeer({ chainId: toChainId(chain) }) + .accounts({ + payer: payer, + config: this.manager.pdas.configAccount(), + peer: this.pdas.transceiverPeerAccount(chain), + wormholeMessage: wormholeMessage, + emitter: whAccs.wormholeEmitter, + wormhole: { + bridge: whAccs.wormholeBridge, + feeCollector: whAccs.wormholeFeeCollector, + sequence: whAccs.wormholeSequence, + program: this.manager.core.address, + }, + }) + .instruction(); + } + + async createReleaseWormholeOutboundIx( + payer: PublicKey, + outboxItem: PublicKey, + revertOnDelay: boolean + ): Promise { + const [major, , ,] = parseVersion(this.version); + const whAccs = utils.getWormholeDerivedAccounts( + this.program.programId, + this.manager.core.address + ); + + return this.program.methods + .releaseWormholeOutbound({ + revertOnDelay: revertOnDelay, + }) + .accounts({ + payer, + config: { config: this.manager.pdas.configAccount() }, + outboxItem, + wormholeMessage: this.pdas.wormholeMessageAccount(outboxItem), + emitter: whAccs.wormholeEmitter, + transceiver: this.manager.pdas.registeredTransceiver( + this.program.programId + ), + wormhole: { + bridge: whAccs.wormholeBridge, + feeCollector: whAccs.wormholeFeeCollector, + sequence: whAccs.wormholeSequence, + program: this.manager.core.address, + }, + // NOTE: baked-in transceiver case is handled separately + // due to tx size error when LUT is not configured + ...(major >= 3 && { + manager: this.manager.program.programId, + outboxItemSigner: this.pdas.outboxItemSigner(), + }), + }) + .instruction(); + } } export class SolanaNtt @@ -107,18 +339,20 @@ export class SolanaNtt quoter?: NttQuoter; addressLookupTable?: AddressLookupTableAccount; + // 0 = Wormhole xcvr + transceivers: Program>[]; + // NOTE: these are stored from the constructor, but are not used directly // (only in verifyAddresses) private managerAddress: string; private tokenAddress: string; - private whTransceiverAddress?: string; constructor( readonly network: N, readonly chain: C, readonly connection: Connection, readonly contracts: Contracts & { ntt?: Ntt.Contracts }, - readonly version: string = "2.0.0" + readonly version: string = "3.0.0" ) { if (!contracts.ntt) throw new Error("Ntt contracts not found"); @@ -128,9 +362,59 @@ export class SolanaNtt version as IdlVersion ); + this.transceivers = []; + if ( + "wormhole" in contracts.ntt.transceiver && + contracts.ntt.transceiver["wormhole"] + ) { + const transceiverTypes = [ + "wormhole", // wormhole xcvr should be ix 0 + ...Object.keys(contracts.ntt.transceiver).filter((transceiverType) => { + transceiverType !== "wormhole"; + }), + ]; + transceiverTypes.map((transceiverType) => { + // we currently only support wormhole transceivers + if (transceiverType !== "wormhole") { + throw new Error(`Unsupported transceiver type: ${transceiverType}`); + } + + const transceiverKey = new PublicKey( + contracts.ntt!.transceiver[transceiverType]! + ); + // handle emitterAccount case separately + if (!PublicKey.isOnCurve(transceiverKey)) { + const whTransceiver = new SolanaNttWormholeTransceiver( + this, + getTransceiverProgram( + connection, + contracts.ntt!.manager, + version as IdlVersion + ), + version + ); + if (!whTransceiver.pdas.emitterAccount().equals(transceiverKey)) { + throw new Error( + `Invalid emitterAccount provided. Expected: ${whTransceiver.pdas + .emitterAccount() + .toBase58()}; Actual: ${transceiverKey.toBase58()}` + ); + } + this.transceivers.push(whTransceiver.program); + } else { + this.transceivers.push( + getTransceiverProgram( + connection, + contracts.ntt!.transceiver[transceiverType]!, + version as IdlVersion + ) + ); + } + }); + } + this.managerAddress = contracts.ntt.manager; this.tokenAddress = contracts.ntt.token; - this.whTransceiverAddress = contracts.ntt.transceiver.wormhole; if (this.contracts.ntt?.quoter) this.quoter = new NttQuoter( @@ -148,14 +432,30 @@ export class SolanaNtt this.pdas = NTT.pdas(this.program.programId); } - async getTransceiver(ix: number): Promise | null> { - if (ix !== 0) return null; - if (this.whTransceiverAddress === undefined) return null; + async getTransceiver( + ix: T + ): Promise< + | (T extends 0 + ? SolanaNttWormholeTransceiver + : SolanaNttTransceiver) + | null + > { + const transceiverProgram = this.transceivers[ix] ?? null; + if (!transceiverProgram) return null; + if (ix === 0) + return new SolanaNttWormholeTransceiver( + this, + transceiverProgram, + this.version + ); + return null; + } - return new SolanaNttWormholeTransceiver( - this, - new PublicKey(this.whTransceiverAddress) - ); + async getWormholeTransceiver(): Promise | null> { + return this.getTransceiver(0); } async getMode(): Promise { @@ -221,7 +521,7 @@ export class SolanaNtt } async *setPauser(_newPauser: AnySolanaAddress, _payer: AccountAddress) { - throw new Error("Pauser role not supported on Solna."); + throw new Error("Pauser role not supported on Solana."); } async isRelayingAvailable(destination: Chain): Promise { @@ -319,7 +619,7 @@ export class SolanaNtt ); } catch (e) { // This might happen if e.g. the program is not deployed yet. - const version = "2.0.0"; + const version = "3.0.0"; return version; } } @@ -366,10 +666,21 @@ export class SolanaNtt async *initializeOrUpdateLUT(args: { payer: PublicKey }) { const config = await this.getConfig(); - const ix = await NTT.initializeOrUpdateLUT(this.program, config, { - payer: args.payer, - wormholeId: new PublicKey(this.core.address), - }); + const whTransceiver = await this.getWormholeTransceiver(); + if (!whTransceiver) { + throw new Error("wormhole transceiver not found"); + } + const whTransceiverProgramId = whTransceiver.programId; + + const ix = await NTT.initializeOrUpdateLUT( + this.program, + config, + whTransceiverProgramId, + { + payer: args.payer, + wormholeId: new PublicKey(this.core.address), + } + ); // Already up to date if (!ix) return; @@ -379,54 +690,25 @@ export class SolanaNtt yield this.createUnsignedTx({ transaction: tx }, "Ntt.InitializeLUT"); } - async *registerTransceiver(args: { + async *registerWormholeTransceiver(args: { payer: AccountAddress; owner: AccountAddress; - transceiver: PublicKey; }) { - const config = await this.getConfig(); const payer = new SolanaAddress(args.payer).unwrap(); const owner = new SolanaAddress(args.owner).unwrap(); + + const config = await this.getConfig(); if (config.paused) throw new Error("Contract is paused"); - const ix = await this.program.methods - .registerTransceiver() - .accountsStrict({ - payer, - owner, - config: this.pdas.configAccount(), - transceiver: args.transceiver, - registeredTransceiver: this.pdas.registeredTransceiver( - args.transceiver - ), - systemProgram: SystemProgram.programId, - }) - .instruction(); + const ix = await this.createRegisterTransceiverIx(0, payer, owner); + const whTransceiver = (await this.getWormholeTransceiver())!; const wormholeMessage = Keypair.generate(); - const whAccs = utils.getWormholeDerivedAccounts( - this.program.programId, - this.core.address + const broadcastIx = await whTransceiver.createBroadcastWormholeIdIx( + payer, + config, + wormholeMessage.publicKey ); - const broadcastIx = await this.program.methods - .broadcastWormholeId() - .accountsStrict({ - payer, - config: this.pdas.configAccount(), - mint: config.mint, - wormholeMessage: wormholeMessage.publicKey, - emitter: this.pdas.emitterAccount(), - wormhole: { - bridge: whAccs.wormholeBridge, - feeCollector: whAccs.wormholeFeeCollector, - sequence: whAccs.wormholeSequence, - program: this.core.address, - systemProgram: SystemProgram.programId, - clock: web3.SYSVAR_CLOCK_PUBKEY, - rent: web3.SYSVAR_RENT_PUBKEY, - }, - }) - .instruction(); const tx = new Transaction(); tx.feePayer = payer; @@ -437,21 +719,49 @@ export class SolanaNtt ); } + // TODO: maybe add to Ntt interface + async createRegisterTransceiverIx( + ix: number, + payer: web3.PublicKey, + owner: web3.PublicKey + ): Promise { + const transceiver = await this.getTransceiver(ix); + if (!transceiver) { + throw new Error(`Transceiver not found`); + } + const transceiverProgramId = transceiver.programId; + + return this.program.methods + .registerTransceiver() + .accountsStrict({ + payer, + owner, + config: this.pdas.configAccount(), + transceiver: transceiverProgramId, + registeredTransceiver: + this.pdas.registeredTransceiver(transceiverProgramId), + systemProgram: SystemProgram.programId, + }) + .instruction(); + } + async *setWormholeTransceiverPeer( peer: ChainAddress, payer: AccountAddress ) { - const sender = new SolanaAddress(payer).unwrap(); - yield this.createUnsignedTx( - await NTT.setWormholeTransceiverPeer(this.program, { - wormholeId: new PublicKey(this.core.address), - payer: sender, - owner: sender, - chain: peer.chain, - address: peer.address.toUniversalAddress().toUint8Array(), - }), - "Ntt.SetWormholeTransceiverPeer" - ); + yield* this.setTransceiverPeer(0, peer, payer); + } + + async *setTransceiverPeer( + ix: number, + peer: ChainAddress, + payer: AccountAddress + ) { + const transceiver = await this.getTransceiver(ix); + if (!transceiver) { + throw new Error("Transceiver not found"); + } + yield* transceiver.setPeer(peer, payer); } async *setPeer( @@ -512,6 +822,7 @@ export class SolanaNtt config.tokenProgram ); + const asyncIxs: Promise[] = []; const transferIx = config.mode.locking != null ? NTT.createTransferLockInstruction( @@ -526,21 +837,26 @@ export class SolanaNtt txArgs, this.pdas ); + asyncIxs.push(transferIx); - const releaseIx = NTT.createReleaseOutboundInstruction( - this.program, - { - payer: payerAddress, - outboxItem: outboxItem.publicKey, - revertOnDelay: !options.queue, - wormholeId: new PublicKey(this.core.address), - }, - this.pdas - ); + for (let ix = 0; ix < this.transceivers.length; ++ix) { + if (ix === 0) { + const whTransceiver = await this.getWormholeTransceiver(); + if (!whTransceiver) { + throw new Error("wormhole transceiver not found"); + } + const releaseIx = whTransceiver.createReleaseWormholeOutboundIx( + payerAddress, + outboxItem.publicKey, + !options.queue + ); + asyncIxs.push(releaseIx); + } + } const tx = new Transaction(); tx.feePayer = payerAddress; - tx.add(approveIx, ...(await Promise.all([transferIx, releaseIx]))); + tx.add(approveIx, ...(await Promise.all(asyncIxs))); if (options.automatic) { if (!this.quoter) @@ -555,7 +871,7 @@ export class SolanaNtt outboxItem.publicKey, destination.chain, Number(fee) / LAMPORTS_PER_SOL, - // Note: quoter expects gas dropoff to be in terms of gwei + // NOTE: quoter expects gas dropoff to be in terms of gwei Number(options.gasDropoff ?? 0n) / WEI_PER_GWEI ); tx.add(relayIx); @@ -566,12 +882,10 @@ export class SolanaNtt luts.push(await this.getAddressLookupTable()); } catch {} - const { blockhash } = await this.connection.getLatestBlockhash(); - const messageV0 = new TransactionMessage({ payerKey: payerAddress, instructions: tx.instructions, - recentBlockhash: blockhash, + recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash, }).compileToV0Message(luts); const vtx = new VersionedTransaction(messageV0); @@ -620,83 +934,93 @@ export class SolanaNtt const config = await this.getConfig(); if (config.paused) throw new Error("Contract is paused"); - // TODO: not this, we should iterate over the set of enabled xcvrs? - // if (attestations.length !== this.xcvrs.length) throw "No"; - const wormholeNTT = attestations[0]; - if (!wormholeNTT || wormholeNTT.payloadName !== "WormholeTransfer") { - throw new Error("Invalid attestation payload"); + if (attestations.length !== this.transceivers.length) { + throw new Error("Not enough attestations provided"); } - // Create the vaa if necessary - yield* this.createAta(payer); - - // Post the VAA that we intend to redeem - yield* this.core.postVaa(payer, wormholeNTT); - - const senderAddress = new SolanaAddress(payer).unwrap(); - - const receiveMessageIx = NTT.createReceiveWormholeMessageInstruction( - this.program, - { - wormholeId: new PublicKey(this.core.address), - payer: senderAddress, - vaa: wormholeNTT, - }, - this.pdas - ); - - const nttMessage = wormholeNTT.payload.nttManagerPayload; - const emitterChain = wormholeNTT.emitterChain; - const releaseArgs = { - payer: senderAddress, - config, - nttMessage, - recipient: new PublicKey( - nttMessage.payload.recipientAddress.toUint8Array() - ), - chain: emitterChain, - revertOnDelay: false, - }; - - // TODO: loop through transceivers etc. - const redeemIx = NTT.createRedeemInstruction(this.program, config, { - payer: senderAddress, - vaa: wormholeNTT, - }); - - const releaseIx = - config.mode.locking != null - ? NTT.createReleaseInboundUnlockInstruction( - this.program, - config, - releaseArgs - ) - : NTT.createReleaseInboundMintInstruction( - this.program, - config, - releaseArgs - ); + for (const { attestation, ix } of attestations.map((attestation, ix) => ({ + attestation, + ix, + }))) { + if (ix === 0) { + const wormholeNTT = attestation; + if (wormholeNTT.payloadName !== "WormholeTransfer") { + throw new Error("Invalid attestation payload"); + } + const whTransceiver = await this.getWormholeTransceiver(); + if (!whTransceiver) { + throw new Error("wormhole transceiver not found"); + } - const tx = new Transaction(); - tx.feePayer = senderAddress; - tx.add(...(await Promise.all([receiveMessageIx, redeemIx, releaseIx]))); + // Create the vaa if necessary + yield* this.createAta(payer); - const luts: AddressLookupTableAccount[] = []; - try { - luts.push(await this.getAddressLookupTable()); - } catch {} + // Post the VAA that we intend to redeem + yield* this.core.postVaa(payer, wormholeNTT); - const { blockhash } = await this.connection.getLatestBlockhash(); + const senderAddress = new SolanaAddress(payer).unwrap(); - const messageV0 = new TransactionMessage({ - payerKey: senderAddress, - instructions: tx.instructions, - recentBlockhash: blockhash, - }).compileToV0Message(luts); + const receiveMessageIx = whTransceiver.createReceiveIx( + wormholeNTT, + senderAddress + ); - const vtx = new VersionedTransaction(messageV0); + const redeemIx = NTT.createRedeemInstruction( + this.program, + config, + whTransceiver.program.programId, + { + payer: senderAddress, + vaa: wormholeNTT, + } + ); - yield this.createUnsignedTx({ transaction: vtx }, "Ntt.Redeem"); + const nttMessage = wormholeNTT.payload.nttManagerPayload; + const emitterChain = wormholeNTT.emitterChain; + const releaseArgs = { + payer: senderAddress, + config, + nttMessage, + recipient: new PublicKey( + nttMessage.payload.recipientAddress.toUint8Array() + ), + chain: emitterChain, + revertOnDelay: false, + }; + const releaseIx = + config.mode.locking != null + ? NTT.createReleaseInboundUnlockInstruction( + this.program, + config, + releaseArgs + ) + : NTT.createReleaseInboundMintInstruction( + this.program, + config, + releaseArgs + ); + + const tx = new Transaction(); + tx.feePayer = senderAddress; + tx.add(...(await Promise.all([receiveMessageIx, redeemIx, releaseIx]))); + + const luts: AddressLookupTableAccount[] = []; + try { + luts.push(await this.getAddressLookupTable()); + } catch {} + + const messageV0 = new TransactionMessage({ + payerKey: senderAddress, + instructions: tx.instructions, + recentBlockhash: (await this.connection.getLatestBlockhash()) + .blockhash, + }).compileToV0Message(luts); + + const vtx = new VersionedTransaction(messageV0); + + yield this.createUnsignedTx({ transaction: vtx }, "Ntt.Redeem"); + } + } } async getCurrentOutboundCapacity(): Promise { @@ -890,18 +1214,28 @@ export class SolanaNtt } async verifyAddresses(): Promise | null> { + // NOTE: This function should only be called when the wormhole transceiver is the manager. + // For the generic transceiver case, transceivers can not be compared as there is no + // reverse lookup given manager address to the registered transceivers. + const whTransceiver = await this.getWormholeTransceiver(); const local: Partial = { manager: this.managerAddress, token: this.tokenAddress, transceiver: { - wormhole: this.whTransceiverAddress, + ...(whTransceiver && { + wormhole: whTransceiver.pdas.emitterAccount().toBase58(), + }), }, }; const remote: Partial = { manager: this.program.programId.toBase58(), token: (await this.getConfig()).mint.toBase58(), - transceiver: { wormhole: this.pdas.emitterAccount().toBase58() }, + transceiver: { + wormhole: NTT.transceiverPdas(this.program.programId) + .emitterAccount() + .toBase58(), + }, }; const deleteMatching = (a: any, b: any) => {