UNPKG

@layerzerolabs/lz-sui-sdk-v2

Version:

1,171 lines (1,090 loc) 42.3 kB
import { bcs } from '@mysten/sui/bcs' import { SuiClient } from '@mysten/sui/client' import { Transaction, TransactionArgument, TransactionResult } from '@mysten/sui/transactions' import { DstConfigBcs } from '../../bcs' import { ModuleManager } from '../../module-manager' import { DstConfig, NativeDropParams, ObjectOptions } from '../../types' import { asAddress, asArgWithTx, asBool, asBytes, asBytes32, asObject, asU128, asU16, asU32, asU64, executeSimulate, } from '../../utils' const MODULE_NAME = 'executor_worker' export const ExecutorErrorCode = { // Executor related errors (with Executor_ prefix) Executor_EEidNotSupported: 1, Executor_EInvalidNativeDropAmount: 2, // ExecutorInfoV1 related errors (matching executor_info_v1.move) ExecutorInfoV1_EInvalidData: 1, ExecutorInfoV1_EInvalidVersion: 2, } as const export class Executor { public packageId: string public readonly client: SuiClient private readonly objects: ObjectOptions constructor( packageId: string, client: SuiClient, objects: ObjectOptions, private readonly moduleManager: ModuleManager ) { this.packageId = packageId this.client = client this.objects = objects } // === Witness Functions === /** * Create a LayerZero witness for Executor package whitelist registration * @param tx - The transaction to add the move call to * @returns Transaction result containing the LayerZero witness */ createLayerZeroWitnessMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: `${this.packageId}::executor_witness::new`, arguments: [], }) } // Job Assignment and Fee Functions /** * Assign execution job for Executor (called via PTB with Call created by send function in ULN302) * @param tx - The transaction to add the move call to * @param call - The call transaction result from ULN302 * @returns Transaction result containing the job assignment call */ assignJobMoveCall(tx: Transaction, call: TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('assign_job'), arguments: [tx.object(this.objects.executor), call], }) } /** * Confirm assign job operation with fee calculation * @param tx - The transaction to add the move call to * @param executorCall - The executor call transaction result * @param feelibCall - The fee library call transaction result */ confirmAssignJobMoveCall( tx: Transaction, executorCall: TransactionArgument, feelibCall: TransactionArgument ): void { tx.moveCall({ target: this.#target('confirm_assign_job'), arguments: [tx.object(this.objects.executor), executorCall, feelibCall], }) } /** * Get fee for execution (using Call created by quote function in ULN302) * @param tx - The transaction to add the move call to * @param call - The call transaction result from ULN302 * @returns Transaction result containing the fee calculation call */ getFeeMoveCall(tx: Transaction, call: TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('get_fee'), arguments: [tx.object(this.objects.executor), call], }) } /** * Confirm get fee operation with fee library * @param tx - The transaction to add the move call to * @param executorCall - The executor call transaction result * @param feelibCall - The fee library call transaction result */ confirmGetFeeMoveCall(tx: Transaction, executorCall: TransactionArgument, feelibCall: TransactionArgument): void { tx.moveCall({ target: this.#target('confirm_get_fee'), arguments: [tx.object(this.objects.executor), executorCall, feelibCall], }) } // Execution Functions /** * Execute LayerZero receive operation (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param messagingChannel - The messaging channel object ID * @param srcEid - Source endpoint ID * @param sender - Sender address as bytes * @param nonce - Message nonce * @param guid - Globally unique identifier as bytes * @param message - Message payload as bytes * @param extraData - Additional execution data (optional) * @param value - Native token value to transfer * @returns Transaction result containing the execution call capability */ executeLzReceiveMoveCall( tx: Transaction, adminCap: string | TransactionArgument, messagingChannel: string | TransactionArgument, srcEid: number | TransactionArgument, sender: Uint8Array | TransactionArgument, nonce: bigint | number | string | TransactionArgument, guid: Uint8Array | TransactionArgument, message: Uint8Array | TransactionArgument, extraData: Uint8Array | TransactionArgument = new Uint8Array(), value = 0n ): TransactionResult { return tx.moveCall({ target: this.#target('execute_lz_receive'), arguments: [ tx.object(this.objects.executor), asObject(tx, adminCap), tx.object(this.objects.endpointV2), asObject(tx, messagingChannel), asU32(tx, srcEid), asBytes32(tx, sender, this.moduleManager.getUtils()), asU64(tx, nonce), asBytes32(tx, guid, this.moduleManager.getUtils()), asBytes(tx, message), asBytes(tx, extraData), asArgWithTx(tx, value, (tx, val) => this.moduleManager.getUtils().createOptionSuiMoveCall(tx, val)), ], }) } /** * Execute LayerZero compose operation (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param composeQueue - The compose queue object ID * @param from - Source address * @param guid - Globally unique identifier as bytes * @param index - Compose message index * @param message - Message payload as bytes * @param extraData - Additional execution data (optional) * @param value - Native token value to transfer * @returns Transaction result containing the execution call capability */ executeLzComposeMoveCall( tx: Transaction, adminCap: string | TransactionArgument, composeQueue: string | TransactionArgument, from: string | TransactionArgument, guid: Uint8Array | TransactionArgument, index: number | TransactionArgument, message: Uint8Array | TransactionArgument, extraData: Uint8Array | TransactionArgument = new Uint8Array(), value = 0n ): TransactionResult { return tx.moveCall({ target: this.#target('execute_lz_compose'), arguments: [ tx.object(this.objects.executor), asObject(tx, adminCap), tx.object(this.objects.endpointV2), asObject(tx, composeQueue), asAddress(tx, from), asBytes32(tx, guid, this.moduleManager.getUtils()), asU16(tx, index), asBytes(tx, message), asBytes(tx, extraData), asArgWithTx(tx, value, (tx, val) => this.moduleManager.getUtils().createOptionSuiMoveCall(tx, val)), ], }) } // Alert Functions /** * Record a failed lz_receive execution for off-chain processing (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param srcEid - Source endpoint ID * @param sender - Sender address as bytes * @param nonce - Message nonce * @param receiver - Receiver address * @param guid - Globally unique identifier as bytes * @param gas - Gas limit used for the execution attempt * @param value - Native token value included with the message * @param message - Message payload as bytes * @param extraData - Additional execution data * @param reason - Error message or failure reason */ lzReceiveAlertMoveCall( tx: Transaction, adminCap: string | TransactionArgument, srcEid: number | TransactionArgument, sender: Uint8Array | TransactionArgument, nonce: bigint | number | string | TransactionArgument, receiver: string | TransactionArgument, guid: Uint8Array | TransactionArgument, gas: bigint | number | string | TransactionArgument, value: bigint | number | string | TransactionArgument, message: Uint8Array | TransactionArgument, extraData: Uint8Array | TransactionArgument, reason: string | TransactionArgument ): void { tx.moveCall({ target: this.#target('lz_receive_alert'), arguments: [ tx.object(this.objects.executor), asObject(tx, adminCap), asU32(tx, srcEid), asBytes32(tx, sender, this.moduleManager.getUtils()), asU64(tx, nonce), asAddress(tx, receiver), asBytes32(tx, guid, this.moduleManager.getUtils()), asU64(tx, gas), asU64(tx, value), asBytes(tx, message), asBytes(tx, extraData), asArgWithTx(tx, reason, (tx, val) => tx.pure.string(val)), ], }) } /** * Record a failed lz_compose execution for off-chain processing (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param from - Source address * @param to - Destination address * @param guid - Globally unique identifier as bytes * @param index - Compose message index * @param gas - Gas limit used for the execution attempt * @param value - Native token value included with the compose * @param message - Compose message payload as bytes * @param extraData - Additional execution data * @param reason - Error message or failure reason */ lzComposeAlertMoveCall( tx: Transaction, adminCap: string | TransactionArgument, from: string | TransactionArgument, to: string | TransactionArgument, guid: Uint8Array | TransactionArgument, index: number | TransactionArgument, gas: bigint | number | string | TransactionArgument, value: bigint | number | string | TransactionArgument, message: Uint8Array | TransactionArgument, extraData: Uint8Array | TransactionArgument, reason: string | TransactionArgument ): void { tx.moveCall({ target: this.#target('lz_compose_alert'), arguments: [ tx.object(this.objects.executor), asObject(tx, adminCap), asAddress(tx, from), asAddress(tx, to), asBytes32(tx, guid, this.moduleManager.getUtils()), asU16(tx, index), asU64(tx, gas), asU64(tx, value), asBytes(tx, message), asBytes(tx, extraData), asArgWithTx(tx, reason, (tx, val) => tx.pure.string(val)), ], }) } // Native Drop Functions /** * Native drop function (admin only) * Takes a Coin<SUI> from caller and distributes it to recipients according to params * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param srcEid - Source endpoint ID * @param sender - Sender address as bytes * @param dstEid - Destination endpoint ID * @param oapp - OApp address * @param nonce - Message nonce * @param nativeDropParams - Array of native drop parameters * @param paymentCoin - Payment coin for the drop */ nativeDropMoveCall( tx: Transaction, adminCap: string | TransactionArgument, srcEid: number | TransactionArgument, sender: Uint8Array | TransactionArgument, dstEid: number | TransactionArgument, oapp: string | TransactionArgument, nonce: bigint | number | string | TransactionArgument, nativeDropParams: NativeDropParams[], paymentCoin: TransactionArgument ): void { // Create individual NativeDropParams move calls for each parameter const dropParamCalls = nativeDropParams.map((param) => tx.moveCall({ target: this.#target('new_native_drop_params', 'native_drop_type'), arguments: [asAddress(tx, param.receiver), asU64(tx, param.amount)], }) ) tx.moveCall({ target: this.#target('native_drop'), arguments: [ tx.object(this.objects.executor), asObject(tx, adminCap), asU32(tx, srcEid), asBytes32(tx, sender, this.moduleManager.getUtils()), asU32(tx, dstEid), asAddress(tx, oapp), asU64(tx, nonce), tx.makeMoveVec({ type: `${this.packageId}::native_drop_type::NativeDropParams`, elements: dropParamCalls, }), paymentCoin, ], }) } // === Set Functions === /** * Set default multiplier basis points for fee calculation (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param multiplierBps - The multiplier in basis points */ setDefaultMultiplierBpsMoveCall( tx: Transaction, adminCap: string | TransactionArgument, multiplierBps: number | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_default_multiplier_bps'), arguments: [tx.object(this.objects.executor), asObject(tx, adminCap), asU16(tx, multiplierBps)], }) } /** * Set deposit address for executor fees (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param depositAddress - The new deposit address */ setDepositAddressMoveCall( tx: Transaction, adminCap: string | TransactionArgument, depositAddress: string | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_deposit_address'), arguments: [tx.object(this.objects.executor), asObject(tx, adminCap), asAddress(tx, depositAddress)], }) } /** * Set destination configuration for executor (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param dstEid - Destination endpoint ID * @param config - Destination configuration parameters */ setDstConfigMoveCall( tx: Transaction, adminCap: string | TransactionArgument, dstEid: number | TransactionArgument, config: DstConfig ): void { const configCall = tx.moveCall({ target: this.#target('create_dst_config', 'executor_type'), arguments: [ asU64(tx, config.lzReceiveBaseGas), asU64(tx, config.lzComposeBaseGas), asU16(tx, config.multiplierBps), asU128(tx, config.floorMarginUsd), asU128(tx, config.nativeCap), ], }) tx.moveCall({ target: this.#target('set_dst_config'), arguments: [tx.object(this.objects.executor), asObject(tx, adminCap), asU32(tx, dstEid), configCall], }) } /** * Set price feed for executor (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param priceFeed - The price feed address */ setPriceFeedMoveCall( tx: Transaction, adminCap: string | TransactionArgument, priceFeed: string | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_price_feed'), arguments: [tx.object(this.objects.executor), asObject(tx, adminCap), asAddress(tx, priceFeed)], }) } /** * Set PTB builder move calls for executor worker operations (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param targetPtbBuilder - Target PTB builder address * @param getFeeMoveCalls - Get fee move calls transaction argument * @param assignJobMoveCalls - Assign job move calls transaction argument * @returns Transaction result containing the set PTB builder call */ setPtbBuilderMoveCallsMoveCall( tx: Transaction, targetPtbBuilder: string | TransactionArgument, getFeeMoveCalls: TransactionArgument, assignJobMoveCalls: TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('set_ptb_builder_move_calls'), arguments: [ tx.object(this.objects.executor), asObject(tx, this.objects.executorOwnerCap), asAddress(tx, targetPtbBuilder), getFeeMoveCalls, // First element of Executor PTB result tuple assignJobMoveCalls, // Second element of Executor PTB result tuple ], }) } /** * Set supported option types for a destination EID (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param dstEid - Destination endpoint ID * @param optionTypes - Array of supported option type values */ setSupportedOptionTypesMoveCall( tx: Transaction, adminCap: string | TransactionArgument, dstEid: number | TransactionArgument, optionTypes: number[] ): void { tx.moveCall({ target: this.#target('set_supported_option_types'), arguments: [ tx.object(this.objects.executor), asObject(tx, adminCap), asU32(tx, dstEid), tx.pure(bcs.vector(bcs.u8()).serialize(optionTypes)), ], }) } /** * Set worker fee library for executor (admin only) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID * @param workerFeeLib - The worker fee library address */ setWorkerFeeLibMoveCall( tx: Transaction, adminCap: string | TransactionArgument, workerFeeLib: string | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_worker_fee_lib'), arguments: [tx.object(this.objects.executor), asObject(tx, adminCap), asAddress(tx, workerFeeLib)], }) } /** * Set admin role (grant or revoke) (owner only) * @param tx - The transaction to add the move call to * @param ownerCap - The owner capability object ID * @param admin - The admin address * @param active - Whether to grant or revoke admin role */ setAdminMoveCall( tx: Transaction, ownerCap: string | TransactionArgument, admin: string | TransactionArgument, active: boolean | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_admin'), arguments: [ tx.object(this.objects.executor), asObject(tx, ownerCap), asAddress(tx, admin), asBool(tx, active), ], }) } /** * Set supported message library (owner only) * @param tx - The transaction to add the move call to * @param ownerCap - The owner capability object ID * @param messageLib - The message library address * @param supported - Whether to support or remove support for the message library */ setSupportedMessageLibMoveCall( tx: Transaction, ownerCap: string | TransactionArgument, messageLib: string | TransactionArgument, supported: boolean | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_supported_message_lib'), arguments: [ tx.object(this.objects.executor), asObject(tx, ownerCap), asAddress(tx, messageLib), asBool(tx, supported), ], }) } /** * Set allowlist status for an OApp sender (owner only) * @param tx - The transaction to add the move call to * @param ownerCap - The owner capability object ID * @param oapp - The OApp address * @param allowed - Whether to allow or remove from allowlist */ setAllowlistMoveCall( tx: Transaction, ownerCap: string | TransactionArgument, oapp: string | TransactionArgument, allowed: boolean | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_allowlist'), arguments: [ tx.object(this.objects.executor), asObject(tx, ownerCap), asAddress(tx, oapp), asBool(tx, allowed), ], }) } /** * Set denylist status for an OApp sender (owner only) * @param tx - The transaction to add the move call to * @param ownerCap - The owner capability object ID * @param oapp - The OApp address * @param denied - Whether to deny or remove from denylist */ setDenylistMoveCall( tx: Transaction, ownerCap: string | TransactionArgument, oapp: string | TransactionArgument, denied: boolean | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_denylist'), arguments: [ tx.object(this.objects.executor), asObject(tx, ownerCap), asAddress(tx, oapp), asBool(tx, denied), ], }) } /** * Set worker paused state (owner only) * @param tx - The transaction to add the move call to * @param ownerCap - The owner capability object ID * @param paused - Whether to pause or unpause the worker */ setPausedMoveCall( tx: Transaction, ownerCap: string | TransactionArgument, paused: boolean | TransactionArgument ): void { tx.moveCall({ target: this.#target('set_paused'), arguments: [tx.object(this.objects.executor), asObject(tx, ownerCap), asBool(tx, paused)], }) } // === View Functions === /** * Get the size of the allowlist * @param tx - The transaction to add the move call to * @returns Transaction result containing the allowlist size */ allowlistSizeMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('allowlist_size'), arguments: [tx.object(this.objects.executor)], }) } /** * Get the size of the allowlist * @returns Promise<bigint> - The number of addresses in the allowlist */ async allowlistSize(): Promise<bigint> { return executeSimulate( this.client, (tx) => { this.allowlistSizeMoveCall(tx) }, (result) => BigInt(bcs.U64.parse(result[0].value)) ) } /** * Get default multiplier basis points * @param tx - The transaction to add the move call to * @returns Transaction result containing the default multiplier bps */ defaultMultiplierBpsMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('default_multiplier_bps'), arguments: [tx.object(this.objects.executor)], }) } /** * Get default multiplier basis points * @returns Promise<number> - The default multiplier in basis points */ async defaultMultiplierBps(): Promise<number> { return executeSimulate( this.client, (tx) => { this.defaultMultiplierBpsMoveCall(tx) }, (result) => bcs.U16.parse(result[0].value) ) } /** * Get executor deposit address for fee collection * @param tx - The transaction to add the move call to * @returns Transaction result containing the deposit address */ depositAddressMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('deposit_address'), arguments: [tx.object(this.objects.executor)], }) } /** * Get executor deposit address for fee collection * @returns Promise<string> - The deposit address */ async depositAddress(): Promise<string> { return executeSimulate( this.client, (tx) => { this.depositAddressMoveCall(tx) }, (result) => bcs.Address.parse(result[0].value) ) } /** * Get destination configuration for executor * @param tx - The transaction to add the move call to * @param dstEid - Destination endpoint ID * @returns Transaction result containing the destination configuration */ dstConfigMoveCall(tx: Transaction, dstEid: number | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('dst_config'), arguments: [tx.object(this.objects.executor), asU32(tx, dstEid)], }) } /** * Get destination configuration for executor * @param dstEid - Destination endpoint ID * @returns Promise<DstConfig> - The destination configuration */ async dstConfig(dstEid: number): Promise<DstConfig> { return executeSimulate( this.client, (tx) => { this.dstConfigMoveCall(tx, dstEid) }, (result) => this.parseDstConfig(result[0].value) ) } /** * Check if an address has ACL (Access Control List) permission * @param tx - The transaction to add the move call to * @param account - The account address to check * @returns Transaction result containing the ACL permission status */ hasAclMoveCall(tx: Transaction, account: string): TransactionResult { return tx.moveCall({ target: this.#target('has_acl'), arguments: [tx.object(this.objects.executor), asAddress(tx, account)], }) } /** * Check if an address has ACL (Access Control List) permission * @param account - The account address to check * @returns Promise<boolean> - True if the address has ACL permission */ async hasAcl(account: string): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.hasAclMoveCall(tx, account) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Get all registered executor admins * @param tx - The transaction to add the move call to * @returns Transaction result containing array of admin addresses */ adminsMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('admins'), arguments: [tx.object(this.objects.executor)], }) } /** * Get all registered executor admins * @returns Promise<string[]> - Array of admin addresses */ async admins(): Promise<string[]> { return executeSimulate( this.client, (tx) => { this.adminsMoveCall(tx) }, (result) => { const parsed = bcs.vector(bcs.Address).parse(result[0].value) return parsed } ) } /** * Check if an admin cap is valid (sync Move call) * @param tx - The transaction to add the move call to * @param adminCap - The admin capability object ID to check * @returns TransactionResult - Result containing admin status */ isAdminMoveCall(tx: Transaction, adminCap: string | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('is_admin'), arguments: [tx.object(this.objects.executor), asObject(tx, adminCap)], }) } /** * Check if an admin cap is valid (async simulation) * @param adminCap - The admin capability object ID to check * @returns Promise<boolean> - True if the admin cap is valid */ async isAdmin(adminCap: string): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isAdminMoveCall(tx, adminCap) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Check if an address is an admin * @param tx - The transaction to add the move call to * @param admin - The admin address to check * @returns Transaction result containing the admin status */ isAdminAddressMoveCall(tx: Transaction, admin: string | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('is_admin_address'), arguments: [tx.object(this.objects.executor), asAddress(tx, admin)], }) } /** * Check if an address is an admin * @param admin - The admin address to check * @returns Promise<boolean> - True if the address is an admin */ async isAdminAddress(admin: string): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isAdminAddressMoveCall(tx, admin) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Check if a message library is supported by this executor * @param tx - The transaction to add the move call to * @param messageLib - The message library address to check * @returns Transaction result containing the support status */ isSupportedMessageLibMoveCall(tx: Transaction, messageLib: string | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('is_supported_message_lib'), arguments: [tx.object(this.objects.executor), asAddress(tx, messageLib)], }) } /** * Check if a message library is supported by this executor * @param messageLib - The message library address to check * @returns Promise<boolean> - True if the message library is supported */ async isSupportedMessageLib(messageLib: string): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isSupportedMessageLibMoveCall(tx, messageLib) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Check if an address is allowlisted * @param tx - The transaction to add the move call to * @param account - The account address to check * @returns Transaction result containing the allowlist status */ isAllowlistedMoveCall(tx: Transaction, account: string | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('is_allowlisted'), arguments: [tx.object(this.objects.executor), asAddress(tx, account)], }) } /** * Check if an address is in the allowlist * @param account - The account address to check * @returns Promise<boolean> - True if the address is allowlisted */ async isAllowlisted(account: string): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isAllowlistedMoveCall(tx, account) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Check if an address is denylisted * @param tx - The transaction to add the move call to * @param account - The account address to check * @returns Transaction result containing the denylist status */ isDenylistedMoveCall(tx: Transaction, account: string | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('is_denylisted'), arguments: [tx.object(this.objects.executor), asAddress(tx, account)], }) } /** * Check if an address is in the denylist * @param account - The account address to check * @returns Promise<boolean> - True if the address is denylisted */ async isDenylisted(account: string): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isDenylistedMoveCall(tx, account) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Check if executor worker is paused * @param tx - The transaction to add the move call to * @returns Transaction result containing the paused status */ isPausedMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('is_paused'), arguments: [tx.object(this.objects.executor)], }) } /** * Check if executor worker is paused * @returns Promise<boolean> - True if the worker is paused */ async isPaused(): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isPausedMoveCall(tx) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Get executor price feed address * @param tx - The transaction to add the move call to * @returns Transaction result containing the price feed address */ priceFeedMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('price_feed'), arguments: [tx.object(this.objects.executor)], }) } /** * Get executor price feed address * @returns Promise<string> - The price feed address */ async priceFeed(): Promise<string> { return executeSimulate( this.client, (tx) => { this.priceFeedMoveCall(tx) }, (result) => bcs.Address.parse(result[0].value) ) } /** * Get supported option types for a destination EID * @param tx - The transaction to add the move call to * @param dstEid - Destination endpoint ID * @returns Transaction result containing supported option types */ supportedOptionTypesMoveCall(tx: Transaction, dstEid: number | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('supported_option_types'), arguments: [tx.object(this.objects.executor), asU32(tx, dstEid)], }) } /** * Get supported option types for a destination EID * @param dstEid - Destination endpoint ID * @returns Promise<number[]> - Array of supported option types as bytes */ async supportedOptionTypes(dstEid: number): Promise<number[]> { return executeSimulate( this.client, (tx) => { this.supportedOptionTypesMoveCall(tx, dstEid) }, (result) => { const parsed = bcs.vector(bcs.u8()).parse(result[0].value) return Array.from(parsed) } ) } /** * Get executor worker capability address * @param tx - The transaction to add the move call to * @returns Transaction result containing the worker capability address */ workerCapAddressMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('worker_cap_address'), arguments: [tx.object(this.objects.executor)], }) } /** * Get executor worker capability address * @returns Promise<string> - The worker capability address */ async workerCapAddress(): Promise<string> { return executeSimulate( this.client, (tx) => { this.workerCapAddressMoveCall(tx) }, (result) => bcs.Address.parse(result[0].value) ) } /** * Get executor worker fee library address * @param tx - The transaction to add the move call to * @returns Transaction result containing the worker fee library address */ workerFeeLibMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('worker_fee_lib'), arguments: [tx.object(this.objects.executor)], }) } /** * Get executor worker fee library address * @returns Promise<string> - The worker fee library address */ async workerFeeLib(): Promise<string> { return executeSimulate( this.client, (tx) => { this.workerFeeLibMoveCall(tx) }, (result) => bcs.Address.parse(result[0].value) ) } /** * Get admin capability ID from admin address * @param tx - The transaction to add the move call to * @param admin - The admin address * @returns Transaction result containing the admin capability ID */ adminCapIdMoveCall(tx: Transaction, admin: string | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('admin_cap_id'), arguments: [tx.object(this.objects.executor), asAddress(tx, admin)], }) } /** * Get admin capability ID from admin address * @param admin - The admin address * @returns Promise<string> - The admin capability ID */ async adminCapId(admin: string): Promise<string> { return executeSimulate( this.client, (tx) => { this.adminCapIdMoveCall(tx, admin) }, (result) => bcs.Address.parse(result[0].value) ) } /** * Get Executor object address from worker registry using this Executor's worker capability (as a move call) * This function chains Move calls to decode worker info and extract the Executor object address * @param tx - The transaction to add the move call to * @returns Transaction result containing the Executor object address */ getExecutorObjectAddressMoveCall(tx: Transaction): TransactionResult { // Step 1: Get this Executor's worker capability address const workerCapAddress = this.workerCapAddressMoveCall(tx) // Step 2: Get worker info bytes from registry const workerInfoBytes = this.moduleManager .getWorkerRegistry(this.client) .getWorkerInfoMoveCall(tx, workerCapAddress) // Step 3: Decode worker info using worker_common::worker_info_v1::decode const workerInfo = tx.moveCall({ target: `${this.moduleManager.packages.workerCommon}::worker_info_v1::decode`, arguments: [workerInfoBytes], }) // Step 4: Extract worker_info field from decoded WorkerInfoV1 const executorInfoBytes = tx.moveCall({ target: `${this.moduleManager.packages.workerCommon}::worker_info_v1::worker_info`, arguments: [workerInfo], }) // Step 5: Decode Executor info using executor::executor_info_v1::decode const executorInfo = tx.moveCall({ target: `${this.packageId}::executor_info_v1::decode`, arguments: [executorInfoBytes], }) // Step 6: Extract executor_object address from decoded ExecutorInfoV1 return tx.moveCall({ target: `${this.packageId}::executor_info_v1::executor_object`, arguments: [executorInfo], }) } /** * Get Executor object address from worker registry using this Executor's worker capability * This function uses Move calls to decode worker info and extract the Executor object address * @returns Promise<string> - The Executor object address * @throws Will throw an error if worker info is not found or if decoding fails */ async getExecutorObjectAddress(): Promise<string> { return executeSimulate( this.client, (tx) => { this.getExecutorObjectAddressMoveCall(tx) }, (result) => { // The result is the Executor object address directly from the Move call chain return bcs.Address.parse(result[0].value) } ) } // === Private Helper Functions === private parseDstConfig(data: Uint8Array): DstConfig { const config = DstConfigBcs.parse(data) return { lzReceiveBaseGas: BigInt(config.lz_receive_base_gas), lzComposeBaseGas: BigInt(config.lz_compose_base_gas), multiplierBps: config.multiplier_bps, floorMarginUsd: BigInt(config.floor_margin_usd), nativeCap: BigInt(config.native_cap), } } /** * Generate the full target path for move calls * @param name - The function name to call * @param module_name - The module name (defaults to MODULE_NAME) * @returns The full module path for the move call * @private */ #target(name: string, module_name = MODULE_NAME): string { return `${this.packageId}::${module_name}::${name}` } }