UNPKG

@layerzerolabs/lz-sui-sdk-v2

Version:

828 lines (770 loc) 30.1 kB
import { bcs } from '@mysten/sui/bcs' import { SuiClient } from '@mysten/sui/client' import { Transaction, TransactionArgument, TransactionResult } from '@mysten/sui/transactions' import { ExecutorConfigBcs, OAppUlnConfigBcs, UlnConfigBcs } from '../../bcs' import { ModuleManager } from '../../module-manager' import { ExecutorConfig, OAppUlnConfig, ObjectOptions, UlnConfig, VersionInfo } from '../../types' import { asAddress, asAddressVector, asBytes, asBytes32, asObject, asU32, asU64, asU8, executeSimulate, } from '../../utils' const MODULE_NAME = 'uln_302' // ULN-302 specific error codes (matching uln-302 contract files) export const Uln302ErrorCode = { SendUln302_EDefaultExecutorConfigNotFound: 1, SendUln302_EDefaultUlnConfigNotFound: 2, SendUln302_EInvalidMessageSize: 3, SendUln302_EOAppExecutorConfigNotFound: 4, SendUln302_EOAppUlnConfigNotFound: 5, ReceiveUln302_EConfirmationsNotFound: 1, ReceiveUln302_EDefaultUlnConfigNotFound: 2, ReceiveUln302_EInvalidEid: 3, ReceiveUln302_EOAppUlnConfigNotFound: 4, ReceiveUln302_EVerifying: 5, Uln302_EInvalidConfigType: 1, Uln302_EInvalidMessagingChannel: 2, Uln302_EUnsupportedEid: 3, // UlnConfig related errors (matching uln_config.move) UlnConfig_EAtLeastOneDVN: 1, UlnConfig_EDuplicateOptionalDVNs: 2, UlnConfig_EDuplicateRequiredDVNs: 3, UlnConfig_EInvalidOptionalDVNCount: 4, UlnConfig_EInvalidOptionalDVNThreshold: 5, UlnConfig_EInvalidRequiredDVNCount: 6, UlnConfig_EInvalidUlnConfigBytes: 7, // OAppUlnConfig related errors (matching oapp_uln_config.move) OAppUlnConfig_EInvalidConfirmations: 1, OAppUlnConfig_EInvalidRequiredDVNs: 2, OAppUlnConfig_EInvalidOptionalDVNs: 3, // ExecutorConfig related errors (matching executor_config.move) ExecutorConfig_EInvalidExecutorAddress: 1, ExecutorConfig_EInvalidExecutorBytes: 2, ExecutorConfig_EZeroMessageSize: 3, } as const export class Uln302 { 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 } // === Set Functions === /** * Create quote move call for message library * Note: This is typically called by the endpoint, not directly by users * @param tx - The transaction to add the move call to * @param call - The call transaction result containing quote parameters * @returns Transaction result containing the quote operation */ quoteMoveCall(tx: Transaction, call: TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('quote'), arguments: [tx.object(this.objects.uln302), call], }) } /** * Confirm quote move call with worker fee calculations * Note: This is typically called by the endpoint, not directly by users * @param tx - The transaction to add the move call to * @param treasury - Treasury object address * @param messageLibCall - Message library call transaction result * @param executorCall - Executor call transaction result * @param dvnMultiCall - DVN multi-call transaction result */ confirmQuoteMoveCall( tx: Transaction, treasury: string | TransactionArgument, messageLibCall: TransactionArgument, executorCall: TransactionArgument, dvnMultiCall: TransactionArgument ): void { tx.moveCall({ target: this.#target('confirm_quote'), arguments: [ tx.object(this.objects.uln302), asObject(tx, treasury), messageLibCall, executorCall, dvnMultiCall, ], }) } /** * Create send move call for message library * Note: This is typically called by the endpoint, not directly by users * @param tx - The transaction to add the move call to * @param call - The call transaction result containing send parameters * @returns Transaction result containing the send operation */ sendMoveCall(tx: Transaction, call: TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('send'), arguments: [tx.object(this.objects.uln302), call], }) } /** * Confirm send move call with treasury and worker integration * Note: This is typically called by the endpoint, not directly by users * @param tx - The transaction to add the move call to * @param treasury - Treasury object address * @param messagingChannel - The messaging channel object ID * @param endpointCall - The endpoint call transaction result * @param messageLibCall - The message library call transaction result * @param executorCall - The executor call transaction result * @param dvnMultiCall - The DVN multi-call transaction result */ confirmSendMoveCall( tx: Transaction, treasury: string | TransactionArgument, messagingChannel: string | TransactionArgument, endpointCall: TransactionArgument, messageLibCall: TransactionArgument, executorCall: TransactionArgument, dvnMultiCall: TransactionArgument ): void { tx.moveCall({ target: this.#target('confirm_send'), arguments: [ tx.object(this.objects.uln302), tx.object(this.objects.endpointV2), asObject(tx, treasury), asObject(tx, messagingChannel), endpointCall, messageLibCall, executorCall, dvnMultiCall, ], }) } /** * Set configuration move call for ULN302 * Note: This is typically called by the endpoint, not directly by users * @param tx - The transaction to add the move call to * @param call - The call transaction result containing configuration */ setConfigMoveCall(tx: Transaction, call: TransactionArgument): void { tx.moveCall({ target: this.#target('set_config'), arguments: [tx.object(this.objects.uln302), call], }) } /** * Verify packet move call with DVN call (new API) * Note: This is typically called by DVNs via Call objects, not directly by users * @param tx - The transaction to add the move call to * @param verification - The verification object address or transaction argument * @param call - The DVN verification call containing verification parameters */ verifyMoveCall(tx: Transaction, verification: string | TransactionArgument, call: TransactionArgument): void { tx.moveCall({ target: this.#target('verify'), arguments: [tx.object(this.objects.uln302), asObject(tx, verification), call], }) } /** * Commit verification move call after all DVN verifications are complete * Note: This is typically called by relayers/executors, not directly by users * @param tx - The transaction to add the move call to * @param verification - The verification object address * @param messagingChannel - The messaging channel object ID * @param packetHeader - The packet header as bytes * @param payloadHash - The payload hash as bytes */ commitVerificationMoveCall( tx: Transaction, verification: string | TransactionArgument, messagingChannel: string | TransactionArgument, packetHeader: Uint8Array | TransactionArgument, payloadHash: Uint8Array | TransactionArgument ): void { tx.moveCall({ target: this.#target('commit_verification'), arguments: [ tx.object(this.objects.uln302), asObject(tx, verification), tx.object(this.objects.endpointV2), asObject(tx, messagingChannel), asBytes(tx, packetHeader), asBytes32(tx, payloadHash, this.moduleManager.getUtils()), tx.object.clock(), ], }) } /** * Set default executor configuration for destination EID (admin only) * @param tx - The transaction to add the move call to * @param dstEid - Destination endpoint ID or transaction argument * @param config - Executor configuration parameters */ setDefaultExecutorConfigMoveCall( tx: Transaction, dstEid: number | TransactionArgument, config: ExecutorConfig ): void { const executorConfig = this.createExecutorConfigMoveCall(tx, config) tx.moveCall({ target: this.#target('set_default_executor_config'), arguments: [ tx.object(this.objects.uln302), tx.object(this.objects.uln302AdminCap), asU32(tx, dstEid), executorConfig, ], }) } /** * Set default send ULN configuration for destination EID (admin only) * @param tx - The transaction to add the move call to * @param dstEid - Destination endpoint ID or transaction argument * @param config - ULN configuration parameters */ setDefaultSendUlnConfigMoveCall(tx: Transaction, dstEid: number | TransactionArgument, config: UlnConfig): void { const ulnConfig = this.createUlnConfigMoveCall(tx, config) tx.moveCall({ target: this.#target('set_default_send_uln_config'), arguments: [ tx.object(this.objects.uln302), tx.object(this.objects.uln302AdminCap), asU32(tx, dstEid), ulnConfig, ], }) } /** * Set default receive ULN configuration for source EID (admin only) * @param tx - The transaction to add the move call to * @param srcEid - Source endpoint ID or transaction argument * @param config - ULN configuration parameters */ setDefaultReceiveUlnConfigMoveCall(tx: Transaction, srcEid: number | TransactionArgument, config: UlnConfig): void { const ulnConfig = this.createUlnConfigMoveCall(tx, config) tx.moveCall({ target: this.#target('set_default_receive_uln_config'), arguments: [ tx.object(this.objects.uln302), tx.object(this.objects.uln302AdminCap), asU32(tx, srcEid), ulnConfig, ], }) } // === View Functions === /** * Get ULN-302 version information * @param tx - The transaction to add the move call to * @returns Transaction result containing version information */ versionMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('version'), arguments: [], }) } /** * Get ULN-302 version information * @returns Promise<VersionInfo> - Version information with major, minor, and endpoint version */ async version(): Promise<VersionInfo> { return executeSimulate( this.client, (tx) => { this.versionMoveCall(tx) }, (result) => ({ major: BigInt(bcs.U64.parse(result[0].value)), minor: bcs.U8.parse(result[1].value), endpointVersion: bcs.U8.parse(result[2].value), }) ) } /** * Check if endpoint ID is supported by ULN-302 * @param tx - The transaction to add the move call to * @param eid - Endpoint ID to check * @returns Transaction result containing support status */ isSupportedEidMoveCall(tx: Transaction, eid: number | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('is_supported_eid'), arguments: [tx.object(this.objects.uln302), asU32(tx, eid)], }) } /** * Check if endpoint ID is supported by ULN-302 * @param eid - Endpoint ID to check * @returns Promise<boolean> - True if the endpoint ID is supported */ async isSupportedEid(eid: number): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.isSupportedEidMoveCall(tx, eid) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Get default executor configuration for destination EID * @param tx - The transaction to add the move call to * @param dstEid - Destination endpoint ID * @returns Transaction result containing the executor configuration */ getDefaultExecutorConfigMoveCall(tx: Transaction, dstEid: number | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('get_default_executor_config'), arguments: [tx.object(this.objects.uln302), asU32(tx, dstEid)], }) } /** * Get default executor configuration for destination EID */ async getDefaultExecutorConfig(dstEid: number): Promise<ExecutorConfig> { return executeSimulate( this.client, (tx) => { this.getDefaultExecutorConfigMoveCall(tx, dstEid) }, (result) => this.parseExecutorConfig(result[0].value) ) } /** * Get OApp-specific executor configuration * @param tx - The transaction to add the move call to * @param sender - The sender OApp address * @param dstEid - Destination endpoint ID * @returns Transaction result containing the executor configuration */ getOAppExecutorConfigMoveCall( tx: Transaction, sender: string | TransactionArgument, dstEid: number | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_oapp_executor_config'), arguments: [tx.object(this.objects.uln302), asAddress(tx, sender), asU32(tx, dstEid)], }) } /** * Get OApp-specific executor configuration */ async getOAppExecutorConfig(sender: string, dstEid: number): Promise<ExecutorConfig> { return executeSimulate( this.client, (tx) => { this.getOAppExecutorConfigMoveCall(tx, sender, dstEid) }, (result) => this.parseExecutorConfig(result[0].value) ) } /** * Get effective executor configuration (OApp-specific or default) * @param tx - The transaction to add the move call to * @param sender - The sender OApp address * @param dstEid - Destination endpoint ID * @returns Transaction result containing the effective executor configuration */ getEffectiveExecutorConfigMoveCall( tx: Transaction, sender: string | TransactionArgument, dstEid: number | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_effective_executor_config'), arguments: [tx.object(this.objects.uln302), asAddress(tx, sender), asU32(tx, dstEid)], }) } /** * Get effective executor configuration (OApp-specific or default) */ async getEffectiveExecutorConfig(sender: string, dstEid: number): Promise<ExecutorConfig> { return executeSimulate( this.client, (tx) => { this.getEffectiveExecutorConfigMoveCall(tx, sender, dstEid) }, (result) => this.parseExecutorConfig(result[0].value) ) } /** * Get default send ULN configuration for destination EID * @param tx - The transaction to add the move call to * @param dstEid - Destination endpoint ID * @returns Transaction result containing the default send ULN configuration */ getDefaultSendUlnConfigMoveCall(tx: Transaction, dstEid: number | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('get_default_send_uln_config'), arguments: [tx.object(this.objects.uln302), asU32(tx, dstEid)], }) } /** * Get default ULN send configuration */ async getDefaultSendUlnConfig(dstEid: number): Promise<UlnConfig> { return executeSimulate( this.client, (tx) => { this.getDefaultSendUlnConfigMoveCall(tx, dstEid) }, (result) => this.parseUlnConfig(result[0].value) ) } /** * Get OApp-specific send ULN configuration * @param tx - The transaction to add the move call to * @param sender - The sender OApp address * @param dstEid - Destination endpoint ID * @returns Transaction result containing the OApp send ULN configuration */ getOAppSendUlnConfigMoveCall( tx: Transaction, sender: string | TransactionArgument, dstEid: number | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_oapp_send_uln_config'), arguments: [tx.object(this.objects.uln302), asAddress(tx, sender), asU32(tx, dstEid)], }) } /** * Get OApp-specific ULN send configuration */ async getOAppSendUlnConfig(sender: string, dstEid: number): Promise<OAppUlnConfig> { return executeSimulate( this.client, (tx) => { this.getOAppSendUlnConfigMoveCall(tx, sender, dstEid) }, (result) => this.parseOAppUlnConfig(result[0].value) ) } /** * Get effective send ULN configuration (OApp-specific or default) * @param tx - The transaction to add the move call to * @param sender - The sender OApp address * @param dstEid - Destination endpoint ID * @returns Transaction result containing the effective send ULN configuration */ getEffectiveSendUlnConfigMoveCall( tx: Transaction, sender: string | TransactionArgument, dstEid: number | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_effective_send_uln_config'), arguments: [tx.object(this.objects.uln302), asAddress(tx, sender), asU32(tx, dstEid)], }) } /** * Get effective ULN send configuration */ async getEffectiveSendUlnConfig(sender: string, dstEid: number): Promise<UlnConfig> { return executeSimulate( this.client, (tx) => { this.getEffectiveSendUlnConfigMoveCall(tx, sender, dstEid) }, (result) => this.parseUlnConfig(result[0].value) ) } /** * Get default receive ULN configuration for source EID * @param tx - The transaction to add the move call to * @param srcEid - Source endpoint ID * @returns Transaction result containing the default receive ULN configuration */ getDefaultReceiveUlnConfigMoveCall(tx: Transaction, srcEid: number | TransactionArgument): TransactionResult { return tx.moveCall({ target: this.#target('get_default_receive_uln_config'), arguments: [tx.object(this.objects.uln302), asU32(tx, srcEid)], }) } /** * Get default ULN receive configuration */ async getDefaultReceiveUlnConfig(srcEid: number): Promise<UlnConfig> { return executeSimulate( this.client, (tx) => { this.getDefaultReceiveUlnConfigMoveCall(tx, srcEid) }, (result) => this.parseUlnConfig(result[0].value) ) } /** * Get OApp-specific receive ULN configuration * @param tx - The transaction to add the move call to * @param receiver - The receiver OApp address * @param srcEid - Source endpoint ID * @returns Transaction result containing the OApp receive ULN configuration */ getOAppReceiveUlnConfigMoveCall( tx: Transaction, receiver: string | TransactionArgument, srcEid: number | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_oapp_receive_uln_config'), arguments: [tx.object(this.objects.uln302), asAddress(tx, receiver), asU32(tx, srcEid)], }) } /** * Get OApp-specific ULN receive configuration */ async getOAppReceiveUlnConfig(receiver: string, srcEid: number): Promise<OAppUlnConfig> { return executeSimulate( this.client, (tx) => { this.getOAppReceiveUlnConfigMoveCall(tx, receiver, srcEid) }, (result) => this.parseOAppUlnConfig(result[0].value) ) } /** * Get effective receive ULN configuration (OApp-specific or default) * @param tx - The transaction to add the move call to * @param receiver - The receiver OApp address * @param srcEid - Source endpoint ID * @returns Transaction result containing the effective receive ULN configuration */ getEffectiveReceiveUlnConfigMoveCall( tx: Transaction, receiver: string | TransactionArgument, srcEid: number | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_effective_receive_uln_config'), arguments: [tx.object(this.objects.uln302), asAddress(tx, receiver), asU32(tx, srcEid)], }) } /** * Get effective ULN receive configuration */ async getEffectiveReceiveUlnConfig(receiver: string, srcEid: number): Promise<UlnConfig> { return executeSimulate( this.client, (tx) => { this.getEffectiveReceiveUlnConfigMoveCall(tx, receiver, srcEid) }, (result) => this.parseUlnConfig(result[0].value) ) } /** * Get verification object address for ULN-302 * @param tx - The transaction to add the move call to * @returns Transaction result containing the verification object address */ getVerificationMoveCall(tx: Transaction): TransactionResult { return tx.moveCall({ target: this.#target('get_verification'), arguments: [tx.object(this.objects.uln302)], }) } /** * Get verification object address for ULN-302 * @returns Promise<string> - The verification object address */ async getVerification(): Promise<string> { return executeSimulate( this.client, (tx) => { this.getVerificationMoveCall(tx) }, (result) => bcs.Address.parse(result[0].value) ) } /** * Check if packet is verifiable through ULN-302 * @param tx - The transaction to add the move call to * @param verification - The verification object address * @param packetHeader - The packet header as bytes * @param payloadHash - The payload hash as bytes * @returns Transaction result containing the verifiable status */ verifiableMoveCall( tx: Transaction, verification: string | TransactionArgument, packetHeader: Uint8Array | TransactionArgument, payloadHash: Uint8Array | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('verifiable'), arguments: [ tx.object(this.objects.uln302), asObject(tx, verification), tx.object(this.objects.endpointV2), asBytes(tx, packetHeader), asBytes32(tx, payloadHash, this.moduleManager.getUtils()), ], }) } /** * Check if packet is verifiable through ULN-302 * @param verification - Verification object address * @param packetHeader - Packet header as bytes * @param payloadHash - Payload hash as bytes * @returns Promise<boolean> - True if packet is verifiable */ async verifiable(verification: string, packetHeader: Uint8Array, payloadHash: Uint8Array): Promise<boolean> { return executeSimulate( this.client, (tx) => { this.verifiableMoveCall(tx, verification, packetHeader, payloadHash) }, (result) => bcs.Bool.parse(result[0].value) ) } /** * Get confirmations for a specific DVN verification * @param tx - The transaction to add the move call to * @param verification - The verification object address * @param dvn - The DVN address * @param headerHash - The header hash as bytes * @param payloadHash - The payload hash as bytes * @returns Transaction result containing the confirmations count */ getConfirmationsMoveCall( tx: Transaction, verification: string | TransactionArgument, dvn: string | TransactionArgument, headerHash: Uint8Array | TransactionArgument, payloadHash: Uint8Array | TransactionArgument ): TransactionResult { return tx.moveCall({ target: this.#target('get_confirmations'), arguments: [ asObject(tx, verification), asAddress(tx, dvn), asBytes32(tx, headerHash, this.moduleManager.getUtils()), asBytes32(tx, payloadHash, this.moduleManager.getUtils()), ], }) } /** * Get confirmations for a specific DVN verification * @param verification - The verification object address * @param dvn - The DVN address * @param headerHash - The header hash as bytes * @param payloadHash - The payload hash as bytes * @returns Promise<bigint> - The confirmations count */ async getConfirmations( verification: string, dvn: string, headerHash: Uint8Array, payloadHash: Uint8Array ): Promise<bigint> { return executeSimulate( this.client, (tx) => { this.getConfirmationsMoveCall(tx, verification, dvn, headerHash, payloadHash) }, (result) => BigInt(bcs.U64.parse(result[0].value)) ) } // === Private Functions === /** * Create executor configuration move call * @param tx - The transaction to add the move call to * @param config - Executor configuration parameters * @returns Transaction result containing the executor configuration * @private */ private createExecutorConfigMoveCall(tx: Transaction, config: ExecutorConfig): TransactionResult { return tx.moveCall({ target: this.#target('create', 'executor_config'), arguments: [asU64(tx, config.maxMessageSize), asAddress(tx, config.executor)], }) } /** * Create ULN configuration move call * @param tx - The transaction to add the move call to * @param config - ULN configuration parameters * @returns Transaction result containing the ULN configuration * @private */ private createUlnConfigMoveCall(tx: Transaction, config: UlnConfig): TransactionResult { return tx.moveCall({ target: this.#target('create', 'uln_config'), arguments: [ asU64(tx, config.confirmations), asAddressVector(tx, config.requiredDvns), asAddressVector(tx, config.optionalDvns), asU8(tx, config.optionalDvnThreshold), ], }) } /** * Parse executor configuration from BCS data * @param data - Raw BCS data to parse * @returns ExecutorConfig - Parsed executor configuration * @private */ private parseExecutorConfig(data: Uint8Array): ExecutorConfig { const config = ExecutorConfigBcs.parse(data) return { maxMessageSize: Number(config.max_message_size), executor: config.executor, } } /** * Parse ULN configuration from BCS data * @param data - Raw BCS data to parse * @returns UlnConfig - Parsed ULN configuration * @private */ private parseUlnConfig(data: Uint8Array): UlnConfig { const config = UlnConfigBcs.parse(data) return { confirmations: BigInt(config.confirmations), requiredDvns: config.required_dvns, optionalDvns: config.optional_dvns, optionalDvnThreshold: config.optional_dvn_threshold, } } /** * Parse OApp ULN configuration from BCS data * @param data - Raw BCS data to parse * @returns OAppUlnConfig - Parsed OApp ULN configuration * @private */ private parseOAppUlnConfig(data: Uint8Array): OAppUlnConfig { const config = OAppUlnConfigBcs.parse(data) const ulnConfig = config.uln_config return { useDefaultConfirmations: config.use_default_confirmations, useDefaultRequiredDvns: config.use_default_required_dvns, useDefaultOptionalDvns: config.use_default_optional_dvns, ulnConfig: { confirmations: BigInt(ulnConfig.confirmations), requiredDvns: ulnConfig.required_dvns, optionalDvns: ulnConfig.optional_dvns, optionalDvnThreshold: ulnConfig.optional_dvn_threshold, }, } } /** * 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: string = MODULE_NAME): string { return `${this.packageId}::${module_name}::${name}` } }