import { AccountInfo, AccountMeta, Commitment, Connection, GetAccountInfoConfig, PublicKey, TransactionInstruction, } from '@solana/web3.js' import BN from 'bn.js' import { EventPDADeriver, ExecutorPDADeriver, MessageLibPDADeriver, PriceFeedPDADeriver } from './pda-deriver' import { getLzComposeAccountMeta } from './recevie' import { ComposeSentEvent } from '../generated/solita/endpoint/events' import * as accounts from '../generated/solita/executor/accounts' import * as events from '../generated/solita/executor/events' import * as instructions from '../generated/solita/executor/instructions' import * as types from '../generated/solita/executor/types' export * from '../generated/solita/executor' export { accounts, instructions, types, events } /** * Class representing the Executor. */ export class Executor { deriver: ExecutorPDADeriver /** * Creates an instance of the Executor class. * * @param {PublicKey} program - The program public key. */ constructor(public program: PublicKey) { this.deriver = new ExecutorPDADeriver(this.program) } // owner methods /** * Initializes the executor. * * @param {PublicKey} payer - The payer public key. * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} admins - The admin public keys. * @param {PublicKey[]} executors - The executor public keys. * @param {PublicKey[]} msglibs - The message library public keys. * @param {PublicKey} priceFeed - The price feed public key. * * @returns {TransactionInstruction} The transaction instruction. */ initExecutor( payer: PublicKey, owner: PublicKey, admins: PublicKey[], executors: PublicKey[], msglibs: PublicKey[], priceFeed: PublicKey ): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createInitExecutorInstruction( { payer, config: configAccount, } satisfies instructions.InitExecutorInstructionAccounts, { params: { owner, admins, executors, msglibs, priceFeed, } satisfies types.InitExecutorParams, } satisfies instructions.InitExecutorInstructionArgs, this.program ) } /** * Sets the owner. * * @param {PublicKey} owner - The current owner public key. * @param {PublicKey} newOwner - The new owner public key. * * @returns {TransactionInstruction} The transaction instruction. */ setOwner(owner: PublicKey, newOwner: PublicKey): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [newOwner], __kind: 'Owner', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } /** * Sets the admins. * * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} admins - The admin public keys. * * @returns {TransactionInstruction} The transaction instruction. */ setAdmins(owner: PublicKey, admins: PublicKey[]): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [admins], __kind: 'Admins', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } /** * Sets the allow list. * * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} allowlist - The allow list public keys. * * @returns {TransactionInstruction} The transaction instruction. */ setAllowList(owner: PublicKey, allowlist: PublicKey[]): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [allowlist], __kind: 'Allowlist', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } /** * Sets the deny list. * * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} denylist - The deny list public keys. * * @returns {TransactionInstruction} The transaction instruction. */ setDenyList(owner: PublicKey, denylist: PublicKey[]): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [denylist], __kind: 'Denylist', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } /** * Sets the paused state. * * @param {PublicKey} owner - The owner public key. * @param {boolean} paused - The paused state. * * @returns {TransactionInstruction} The transaction instruction. */ setPaused(owner: PublicKey, paused: boolean): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [paused], __kind: 'Paused', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } /** * Sets the executors. * * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} executors - The executor public keys. * * @returns {TransactionInstruction} The transaction instruction. */ setExecutors(owner: PublicKey, executors: PublicKey[]): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [executors], __kind: 'Executors', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } /** * Sets the message libraries by programs. * * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} msglibPrograms - The message library program public keys. * * @returns {TransactionInstruction} The transaction instruction. */ setMsglibByPrograms(owner: PublicKey, msglibPrograms: PublicKey[]): TransactionInstruction { const [configAccount] = this.deriver.config() const msglibPdas = msglibPrograms.map((program) => { return new MessageLibPDADeriver(program).messageLib()[0] }) return this.setMsglibByPDAs(owner, msglibPdas) } /** * Sets the message libraries by PDAs. * * @param {PublicKey} owner - The owner public key. * @param {PublicKey[]} msglibPDAs - The message library PDA public keys. * * @returns {TransactionInstruction} The transaction instruction. */ setMsglibByPDAs(owner: PublicKey, msglibPDAs: PublicKey[]): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createOwnerSetConfigInstruction( { owner, config: configAccount, } satisfies instructions.OwnerSetConfigInstructionAccounts, { params: { fields: [msglibPDAs], __kind: 'Msglibs', } satisfies types.OwnerSetConfigParams, } satisfies instructions.OwnerSetConfigInstructionArgs, this.program ) } // admin methods /** * Sets the default multiplier BPS. * * @param {PublicKey} admin - The admin public key. * @param {number} defaultMultiplierBps - The default multiplier BPS. * * @returns {TransactionInstruction} The transaction instruction. */ setDefaultMultiplierBps(admin: PublicKey, defaultMultiplierBps: number): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createAdminSetConfigInstruction( { admin, config: configAccount, } satisfies instructions.AdminSetConfigInstructionAccounts, { params: { fields: [defaultMultiplierBps], __kind: 'DefaultMultiplierBps', } satisfies types.AdminSetConfigParams, } satisfies instructions.AdminSetConfigInstructionArgs, this.program ) } /** * Sets the destination configurations. * * @param {PublicKey} admin - The admin public key. * @param {types.DstConfig[]} dstConfigs - The destination configurations. * * @returns {TransactionInstruction} The transaction instruction. */ setDstConfig(admin: PublicKey, dstConfigs: types.DstConfig[]): TransactionInstruction { const [configAccount] = this.deriver.config() return instructions.createAdminSetConfigInstruction( { admin, config: configAccount, } satisfies instructions.AdminSetConfigInstructionAccounts, { params: { fields: [dstConfigs], __kind: 'DstConfigs', } satisfies types.AdminSetConfigParams, } satisfies instructions.AdminSetConfigInstructionArgs, this.program ) } /** * Sets the price feed. * * @param {PublicKey} admin - The admin public key. * @param {PublicKey} priceFeedProgram - The price feed program public key. * * @returns {TransactionInstruction} The transaction instruction. */ setPriceFeed(admin: PublicKey, priceFeedProgram: PublicKey): TransactionInstruction { const [configAccount] = this.deriver.config() const [priceFeed] = new PriceFeedPDADeriver(priceFeedProgram).priceFeed() return instructions.createAdminSetConfigInstruction( { admin, config: configAccount, } satisfies instructions.AdminSetConfigInstructionAccounts, { params: { fields: [priceFeed], __kind: 'PriceFeed', } satisfies types.AdminSetConfigParams, } satisfies instructions.AdminSetConfigInstructionArgs, this.program ) } /** * Gets the executor configuration. * * @param {Connection} connection - The connection. * @param {Commitment | GetAccountInfoConfig} [commitmentOrConfig] - The commitment or configuration. * * @returns {Promise} A promise that resolves to the executor configuration or null. */ async getExecutorConfig( connection: Connection, commitmentOrConfig?: Commitment | GetAccountInfoConfig ): Promise { const [configAccount] = this.deriver.config() try { const config = await accounts.ExecutorConfig.fromAccountAddress( connection, configAccount, commitmentOrConfig ) return config } catch (error) { return null } } /** * Gets the quote instruction account meta for CPI. * * @param {PublicKey} priceFeedConfig - The price feed configuration public key. * @param {PublicKey} priceFeedProgram - The price feed program public key. * @param {boolean} payment - Whether payment is required. * * @returns {AccountMeta[]} The account meta array. */ getQuoteIXAccountMetaForCPI( priceFeedConfig: PublicKey, priceFeedProgram: PublicKey, payment: boolean ): AccountMeta[] { const [config] = this.deriver.config() const ixAccounts = instructions.createQuoteExecutorInstructionAccounts( { executorConfig: config, priceFeedConfig, priceFeedProgram: priceFeedProgram, } satisfies instructions.QuoteExecutorInstructionAccounts, this.program ) if (payment) { // if payment is required, the first account is required to be writable to receive the payment ixAccounts[0].isWritable = true } return [ { pubkey: this.program, isWritable: false, isSigner: false, }, ].concat(ixAccounts) } /** * Composes a transaction. * * @param {Connection} connection - The connection. * @param {PublicKey} executor - The executor public key. * @param {PublicKey} endpointProgram - The endpoint program public key. * @param {ComposeSentEvent} event - The compose sent event. * @param {Uint8Array} extraData - The extra data. * @param {BN} [value] - The value. * @param {number} [computeUnits] - The compute units. * @param {Commitment} [commitmentOrConfig] - The commitment or configuration. * * @returns {Promise} A promise that resolves to the transaction instruction. */ async compose( connection: Connection, executor: PublicKey, endpointProgram: PublicKey, event: ComposeSentEvent, extraData: Uint8Array, value: BN = new BN(0), computeUnits = 400000, commitmentOrConfig?: Commitment ): Promise { const [config] = this.deriver.config() const endpointEventDeriver = new EventPDADeriver(endpointProgram) const executorEventDeriver = new EventPDADeriver(this.program) const { to, from, guid, index, message } = event const receiverInfo = await connection.getParsedAccountInfo(to, commitmentOrConfig) const receiverProgram = new PublicKey((receiverInfo.value as AccountInfo).owner) const accounts = await getLzComposeAccountMeta( connection, executor, to, receiverProgram, { from, to, guid, index, message, extraData, }, commitmentOrConfig ) return instructions.createComposeInstruction( { executor, config, endpointProgram, endpointEventAuthority: endpointEventDeriver.eventAuthority()[0], program: this.program, eventAuthority: executorEventDeriver.eventAuthority()[0], anchorRemainingAccounts: [ { pubkey: receiverProgram, isWritable: false, isSigner: false, }, ...accounts, ], } satisfies instructions.ComposeInstructionAccounts, { params: { lzCompose: { to, from, guid, index, message, extraData, }, computeUnits, value, } satisfies types.ComposeParams, } satisfies instructions.ComposeInstructionArgs, this.program ) } }