@veridex/sdk 1.0.0-beta.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +170 -21
- package/README.md +574 -117
- package/dist/EVMClient-DtqvdfUP.d.mts +376 -0
- package/dist/auth/prepareAuth.d.mts +25 -0
- package/dist/auth/prepareAuth.js +2406 -0
- package/dist/auth/prepareAuth.js.map +1 -0
- package/dist/auth/prepareAuth.mjs +151 -0
- package/dist/auth/prepareAuth.mjs.map +1 -0
- package/dist/chains/aptos/index.d.mts +6 -5
- package/dist/chains/aptos/index.js +66 -39
- package/dist/chains/aptos/index.js.map +1 -1
- package/dist/chains/aptos/index.mjs +5 -547
- package/dist/chains/aptos/index.mjs.map +1 -1
- package/dist/chains/avalanche/index.d.mts +137 -0
- package/dist/chains/avalanche/index.js +1555 -0
- package/dist/chains/avalanche/index.js.map +1 -0
- package/dist/chains/avalanche/index.mjs +10 -0
- package/dist/chains/avalanche/index.mjs.map +1 -0
- package/dist/chains/evm/index.d.mts +5 -3
- package/dist/chains/evm/index.js +165 -3
- package/dist/chains/evm/index.js.map +1 -1
- package/dist/chains/evm/index.mjs +8 -1200
- package/dist/chains/evm/index.mjs.map +1 -1
- package/dist/chains/solana/index.d.mts +1 -1
- package/dist/chains/solana/index.js.map +1 -1
- package/dist/chains/solana/index.mjs +4 -486
- package/dist/chains/solana/index.mjs.map +1 -1
- package/dist/chains/stacks/index.d.mts +559 -0
- package/dist/chains/stacks/index.js +1207 -0
- package/dist/chains/stacks/index.js.map +1 -0
- package/dist/chains/stacks/index.mjs +71 -0
- package/dist/chains/stacks/index.mjs.map +1 -0
- package/dist/chains/starknet/index.d.mts +4 -5
- package/dist/chains/starknet/index.js +1 -13
- package/dist/chains/starknet/index.js.map +1 -1
- package/dist/chains/starknet/index.mjs +5 -503
- package/dist/chains/starknet/index.mjs.map +1 -1
- package/dist/chains/sui/index.d.mts +4 -4
- package/dist/chains/sui/index.js +2 -2
- package/dist/chains/sui/index.js.map +1 -1
- package/dist/chains/sui/index.mjs +5 -529
- package/dist/chains/sui/index.mjs.map +1 -1
- package/dist/chunk-5T6KPH7A.mjs +1082 -0
- package/dist/chunk-5T6KPH7A.mjs.map +1 -0
- package/dist/chunk-72ZA3OYQ.mjs +20 -0
- package/dist/chunk-72ZA3OYQ.mjs.map +1 -0
- package/dist/chunk-F3YAGZSW.mjs +269 -0
- package/dist/chunk-F3YAGZSW.mjs.map +1 -0
- package/dist/chunk-GWJRKDSA.mjs +549 -0
- package/dist/chunk-GWJRKDSA.mjs.map +1 -0
- package/dist/chunk-M3MM4YMF.mjs +417 -0
- package/dist/chunk-M3MM4YMF.mjs.map +1 -0
- package/dist/chunk-MLXQHIH2.mjs +426 -0
- package/dist/chunk-MLXQHIH2.mjs.map +1 -0
- package/dist/chunk-N4A2RMUN.mjs +216 -0
- package/dist/chunk-N4A2RMUN.mjs.map +1 -0
- package/dist/chunk-NUWSMJFJ.mjs +179 -0
- package/dist/chunk-NUWSMJFJ.mjs.map +1 -0
- package/dist/chunk-OVMMTL6H.mjs +330 -0
- package/dist/chunk-OVMMTL6H.mjs.map +1 -0
- package/dist/chunk-PDHZ5X5O.mjs +565 -0
- package/dist/chunk-PDHZ5X5O.mjs.map +1 -0
- package/dist/chunk-Q5O3M5LP.mjs +422 -0
- package/dist/chunk-Q5O3M5LP.mjs.map +1 -0
- package/dist/chunk-QDO6NQ7P.mjs +840 -0
- package/dist/chunk-QDO6NQ7P.mjs.map +1 -0
- package/dist/chunk-QT4ZZ4GM.mjs +509 -0
- package/dist/chunk-QT4ZZ4GM.mjs.map +1 -0
- package/dist/chunk-SXXGTQIR.mjs +464 -0
- package/dist/chunk-SXXGTQIR.mjs.map +1 -0
- package/dist/chunk-USDA5JTN.mjs +1249 -0
- package/dist/chunk-USDA5JTN.mjs.map +1 -0
- package/dist/chunk-V636MIV3.mjs +52 -0
- package/dist/chunk-V636MIV3.mjs.map +1 -0
- package/dist/chunk-X7BZMSPQ.mjs +407 -0
- package/dist/chunk-X7BZMSPQ.mjs.map +1 -0
- package/dist/chunk-YCUJZ6Z7.mjs +829 -0
- package/dist/chunk-YCUJZ6Z7.mjs.map +1 -0
- package/dist/constants.d.mts +1 -1
- package/dist/constants.js +26 -12
- package/dist/constants.js.map +1 -1
- package/dist/constants.mjs +16 -375
- package/dist/constants.mjs.map +1 -1
- package/dist/index-DDalBhAm.d.mts +243 -0
- package/dist/index.d.mts +2511 -556
- package/dist/index.js +15216 -10262
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4125 -7839
- package/dist/index.mjs.map +1 -1
- package/dist/passkey.d.mts +182 -0
- package/dist/passkey.js +914 -0
- package/dist/passkey.js.map +1 -0
- package/dist/passkey.mjs +15 -0
- package/dist/passkey.mjs.map +1 -0
- package/dist/payload.js.map +1 -1
- package/dist/payload.mjs +25 -244
- package/dist/payload.mjs.map +1 -1
- package/dist/portfolio-V347KZOL.mjs +13 -0
- package/dist/portfolio-V347KZOL.mjs.map +1 -0
- package/dist/queries/index.js +145 -12
- package/dist/queries/index.js.map +1 -1
- package/dist/queries/index.mjs +14 -1496
- package/dist/queries/index.mjs.map +1 -1
- package/dist/{types-FJL7j6gQ.d.ts → types-B7V5VNbO.d.mts} +6 -2
- package/dist/{types-ChIsqCiw.d.mts → types-DP2CQT8p.d.mts} +12 -1
- package/dist/types.d.mts +16 -0
- package/dist/types.js.map +1 -1
- package/dist/utils.js +25 -11
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +19 -371
- package/dist/utils.mjs.map +1 -1
- package/dist/wormhole.js.map +1 -1
- package/dist/wormhole.mjs +25 -397
- package/dist/wormhole.mjs.map +1 -1
- package/package.json +28 -3
- package/scripts/patch-noble-curves.js +78 -0
- package/dist/chains/aptos/index.d.ts +0 -145
- package/dist/chains/evm/index.d.ts +0 -5
- package/dist/chains/solana/index.d.ts +0 -116
- package/dist/chains/starknet/index.d.ts +0 -172
- package/dist/chains/sui/index.d.ts +0 -182
- package/dist/constants.d.ts +0 -150
- package/dist/index-0NXfbk0z.d.ts +0 -637
- package/dist/index-D0dLVjTA.d.mts +0 -637
- package/dist/index.d.ts +0 -3123
- package/dist/payload.d.ts +0 -125
- package/dist/queries/index.d.ts +0 -148
- package/dist/types-ChIsqCiw.d.ts +0 -565
- package/dist/types-FJL7j6gQ.d.mts +0 -172
- package/dist/types.d.ts +0 -407
- package/dist/utils.d.ts +0 -81
- package/dist/wormhole.d.ts +0 -167
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chains/aptos/AptosClient.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Aptos Chain Client\n * \n * Implementation of ChainClient interface for Aptos blockchain\n * Updated to use @aptos-labs/ts-sdk v5.x\n */\n\nimport { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';\nimport { sha3_256 } from 'js-sha3';\nimport type {\n ChainClient,\n ChainConfig,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n WebAuthnSignature,\n VaultCreationResult,\n} from '../../core/types.js';\nimport { encodeTransferAction, encodeExecuteAction, encodeBridgeAction } from '../../payload.js';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Get Aptos network from string configuration\n * The new SDK works best with built-in network configuration\n */\nfunction getAptosNetworkEnum(network?: string): Network {\n if (network === 'mainnet') return Network.MAINNET;\n if (network === 'devnet') return Network.DEVNET;\n return Network.TESTNET; // Default to testnet\n}\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface AptosClientConfig {\n wormholeChainId: number;\n rpcUrl: string;\n moduleAddress: string; // Veridex Spoke module address\n wormholeCoreBridge: string;\n tokenBridge: string;\n network?: 'mainnet' | 'testnet' | 'devnet';\n}\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n// ============================================================================\n// AptosClient Class\n// ============================================================================\n\n/**\n * Aptos implementation of the ChainClient interface\n */\nexport class AptosClient implements ChainClient {\n private config: ChainConfig;\n private client: Aptos;\n private moduleAddress: string;\n\n constructor(config: AptosClientConfig) {\n // Use SDK's built-in network configuration (more reliable than custom URLs)\n const network = getAptosNetworkEnum(config.network);\n \n this.config = {\n name: `Aptos ${config.network || 'mainnet'}`,\n chainId: config.wormholeChainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl: config.rpcUrl, // Keep for reference, but not used for SDK\n explorerUrl: config.network === 'testnet'\n ? 'https://explorer.aptoslabs.com?network=testnet'\n : 'https://explorer.aptoslabs.com',\n isEvm: false,\n contracts: {\n hub: undefined, // Aptos is a spoke only\n wormholeCoreBridge: config.wormholeCoreBridge,\n tokenBridge: config.tokenBridge,\n },\n };\n\n // Create Aptos client with built-in network configuration\n // This is more reliable than custom fullnode URLs\n const aptosConfig = new AptosConfig({ network });\n this.client = new Aptos(aptosConfig);\n this.moduleAddress = config.moduleAddress;\n }\n\n getConfig(): ChainConfig {\n return this.config;\n }\n\n async getNonce(userKeyHash: string): Promise<bigint> {\n try {\n const vaultAddress = this.computeVaultAddressFromHash(userKeyHash);\n\n // Query vault resource using new SDK\n const resources = await this.client.getAccountResources({ \n accountAddress: vaultAddress \n });\n const vaultResource = resources.find(\n (r: { type: string }) => r.type === `${this.moduleAddress}::vault::Vault`\n );\n \n if (!vaultResource) {\n return 0n;\n }\n\n if (vaultResource && vaultResource.data) {\n const data = vaultResource.data as { nonce?: string | number };\n return BigInt(data.nonce || 0);\n }\n\n return 0n;\n } catch (error) {\n console.error('Error getting nonce:', error);\n return 0n;\n }\n }\n\n async getMessageFee(): Promise<bigint> {\n try {\n // Query Wormhole bridge for message fee\n // For now, return a default estimate\n // TODO: Query on-chain Wormhole config\n return 0n; // Aptos doesn't charge a Wormhole fee in the same way\n } catch (error) {\n console.error('Error getting message fee:', error);\n return 0n;\n }\n }\n\n async buildTransferPayload(params: TransferParams): Promise<string> {\n return encodeTransferAction(\n params.token,\n params.recipient,\n params.amount\n );\n }\n\n async buildExecutePayload(params: ExecuteParams): Promise<string> {\n return encodeExecuteAction(\n params.target,\n params.value,\n params.data\n );\n }\n\n async buildBridgePayload(params: BridgeParams): Promise<string> {\n return encodeBridgeAction(\n params.token,\n params.amount,\n params.destinationChain,\n params.recipient\n );\n }\n\n async dispatch(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n signer: any // Aptos AptosAccount\n ): Promise<DispatchResult> {\n void signature;\n void publicKeyX;\n void publicKeyY;\n void targetChain;\n void actionPayload;\n void nonce;\n void signer;\n throw new Error(\n 'Direct dispatch not supported on Aptos spoke chains. ' +\n 'Actions must be dispatched from the Hub (EVM) chain. ' +\n 'This client is for receiving cross-chain messages only.'\n );\n }\n\n /**\n * Dispatch an action via relayer (gasless)\n * Note: On Aptos, this still goes through the Hub chain\n * Aptos is a spoke-only chain in Veridex architecture\n */\n async dispatchGasless(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n relayerUrl: string\n ): Promise<DispatchResult> {\n // Compute key hash\n const keyHash = this.computeKeyHash(publicKeyX, publicKeyY);\n\n // Build the message that was signed (matches Hub chain format)\n const message = this.buildMessage(keyHash, targetChain, actionPayload, nonce);\n\n // Prepare request for relayer\n const request = {\n messageHash: message,\n r: '0x' + signature.r.toString(16).padStart(64, '0'),\n s: '0x' + signature.s.toString(16).padStart(64, '0'),\n publicKeyX: '0x' + publicKeyX.toString(16).padStart(64, '0'),\n publicKeyY: '0x' + publicKeyY.toString(16).padStart(64, '0'),\n targetChain,\n actionPayload,\n nonce: Number(nonce),\n };\n\n // Submit to relayer\n const response = await fetch(`${relayerUrl}/api/v1/submit`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n const error = await response.json().catch(() => ({ error: response.statusText }));\n throw new Error(`Relayer submission failed: ${error.error || response.statusText}`);\n }\n\n const result = await response.json();\n\n if (!result.success) {\n throw new Error(`Relayer submission failed: ${result.error}`);\n }\n\n return {\n transactionHash: result.txHash,\n sequence: BigInt(result.sequence || '0'),\n userKeyHash: keyHash,\n targetChain,\n };\n }\n\n /**\n * Get vault address from on-chain VaultRegistry.\n * Queries the get_vault_address view function which looks up the vault in the registry.\n */\n async getVaultAddress(userKeyHash: string): Promise<string | null> {\n try {\n // Normalize: remove 0x if present, lowercase, pad to 64 chars, then add 0x\n const rawHex = userKeyHash.startsWith('0x') \n ? userKeyHash.slice(2).toLowerCase()\n : userKeyHash.toLowerCase();\n const keyHashHex = `0x${rawHex.padStart(64, '0')}`;\n \n // First check if vault exists to avoid noisy 400 errors in console\n const existsResponse = await this.client.view({\n payload: {\n function: `${this.moduleAddress}::spoke::vault_exists`,\n typeArguments: [],\n functionArguments: [keyHashHex],\n }\n });\n if (!existsResponse || existsResponse.length === 0 || existsResponse[0] !== true) {\n return null; // Vault doesn't exist\n }\n \n // Vault exists, now get the address\n const response = await this.client.view({\n payload: {\n function: `${this.moduleAddress}::spoke::get_vault_address`,\n typeArguments: [],\n functionArguments: [keyHashHex],\n }\n });\n \n if (response && response.length > 0) {\n const vaultAddress = response[0] as string;\n return vaultAddress;\n }\n\n return null;\n } catch (error: any) {\n // E_VAULT_NOT_FOUND (error code 6) means vault doesn't exist in registry\n if (error?.message?.includes('E_VAULT_NOT_FOUND') || \n error?.message?.includes('error code 6') ||\n error?.status === 404) {\n return null;\n }\n console.error('Error getting vault address from registry:', error);\n return null;\n }\n }\n\n /**\n * @deprecated Use getVaultAddress() instead - this method uses incorrect address derivation.\n * On Aptos, vaults are created as named objects by the relayer, not resource accounts.\n * The vault address depends on which relayer created it, so must be queried on-chain.\n */\n computeVaultAddress(userKeyHash: string): string {\n console.warn(\n 'computeVaultAddress() is deprecated for Aptos. ' +\n 'Use getVaultAddress() to query the on-chain VaultRegistry instead.'\n );\n return this.computeVaultAddressFromHash(userKeyHash);\n }\n\n private computeVaultAddressFromHash(userKeyHash: string): string {\n // NOTE: This is kept for backward compatibility but produces INCORRECT addresses!\n // Aptos spoke uses object::create_named_object(creator, key_hash) where:\n // - creator = relayer address (not module address)\n // - scheme = 0xFD (named object, not 0xFE resource account)\n // The correct approach is to query the VaultRegistry on-chain.\n\n const sourceAddress = this.hexToBytes(this.moduleAddress.replace('0x', ''));\n const seed = this.hexToBytes(userKeyHash.replace('0x', ''));\n const scheme = new Uint8Array([0xFE]); // INCORRECT - kept for backward compat\n\n const combined = new Uint8Array([...sourceAddress, ...seed, ...scheme]);\n const hash = sha3_256(combined);\n\n return '0x' + hash;\n }\n\n /**\n * Convert hex string to Uint8Array (browser-compatible)\n */\n private hexToBytes(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substr(i, 2), 16);\n }\n return bytes;\n }\n\n async vaultExists(userKeyHash: string): Promise<boolean> {\n const address = await this.getVaultAddress(userKeyHash);\n return address !== null;\n }\n\n async createVault(userKeyHash: string, signer: any): Promise<VaultCreationResult> {\n void userKeyHash;\n void signer;\n throw new Error(\n 'Vault creation on Aptos must be done via cross-chain message from Hub. ' +\n 'Use the Hub chain client to dispatch a vault creation action targeting Aptos.'\n );\n }\n\n async createVaultSponsored?(\n userKeyHash: string,\n sponsorPrivateKey: string,\n rpcUrl?: string\n ): Promise<VaultCreationResult> {\n void userKeyHash;\n void sponsorPrivateKey;\n void rpcUrl;\n throw new Error(\n 'Vault creation on Aptos must be done via cross-chain message from Hub. ' +\n 'Use relayer gasless submission to create vault.'\n );\n }\n\n /**\n * Create a vault via the relayer (sponsored/gasless)\n * This is the recommended way to create Aptos vaults\n * \n * The relayer will dispatch a vault creation action from Hub to Aptos spoke\n */\n async createVaultViaRelayer(\n userKeyHash: string,\n relayerUrl: string\n ): Promise<VaultCreationResult> {\n const response = await fetch(`${relayerUrl}/api/v1/aptos/vault`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n userKeyHash,\n chainId: this.config.wormholeChainId,\n }),\n });\n\n const result = await response.json();\n\n if (!response.ok || !result.success) {\n throw new Error(result.error || 'Failed to create vault via relayer');\n }\n\n return {\n address: result.vaultAddress,\n transactionHash: result.transactionHash || '',\n blockNumber: 0,\n gasUsed: 0n,\n alreadyExisted: result.alreadyExists || false,\n sponsoredBy: 'relayer',\n };\n }\n\n /**\n * Get vault info via relayer (includes existence check)\n */\n async getVaultViaRelayer(\n userKeyHash: string,\n relayerUrl: string\n ): Promise<{ vaultAddress: string; exists: boolean }> {\n const response = await fetch(\n `${relayerUrl}/api/v1/aptos/vault/${userKeyHash}?chainId=${this.config.wormholeChainId}`\n );\n\n if (!response.ok) {\n throw new Error('Failed to get vault info from relayer');\n }\n\n const result = await response.json();\n return {\n vaultAddress: result.vaultAddress,\n exists: result.exists,\n };\n }\n\n async estimateVaultCreationGas(userKeyHash: string): Promise<bigint> {\n void userKeyHash;\n // Return APT estimate for vault creation\n // ~0.001 APT for account creation + gas\n return 100_000n; // 0.001 APT in octas (1 APT = 100M octas)\n }\n\n getFactoryAddress(): string | undefined {\n // Aptos uses module addresses, not factory pattern\n return undefined;\n }\n\n getImplementationAddress(): string | undefined {\n // Aptos uses module addresses, not implementation pattern\n return undefined;\n }\n\n // ========================================================================\n // Balance Methods\n // ========================================================================\n\n /**\n * Get native APT balance\n */\n async getNativeBalance(address: string): Promise<bigint> {\n try {\n const resource = await this.client.getAccountResource({\n accountAddress: address,\n resourceType: '0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>'\n });\n\n if (resource && resource.data) {\n const data = resource.data as any;\n return BigInt(data.coin?.value || 0);\n }\n\n return 0n;\n } catch (error) {\n console.error('Error getting native balance:', error);\n return 0n;\n }\n }\n\n /**\n * Get fungible asset (FA) or coin balance\n */\n async getTokenBalance(tokenAddress: string, ownerAddress: string): Promise<bigint> {\n try {\n // Try as Coin type first\n const coinType = tokenAddress.includes('::')\n ? tokenAddress\n : `${tokenAddress}::coin::Coin`;\n\n const resource = await this.client.getAccountResource({\n accountAddress: ownerAddress,\n resourceType: `0x1::coin::CoinStore<${coinType}>`\n });\n\n if (resource && resource.data) {\n const data = resource.data as any;\n return BigInt(data.coin?.value || 0);\n }\n\n return 0n;\n } catch (error) {\n // If Coin query fails, try Fungible Asset (FA) format\n try {\n // FA balances are stored differently\n // Would need to query the FA resource\n console.warn('FA balance query not fully implemented yet');\n return 0n;\n } catch (faError) {\n console.error('Error getting token balance:', error);\n return 0n;\n }\n }\n }\n\n // ========================================================================\n // Utility Methods\n // ========================================================================\n\n /**\n * Compute key hash from public key coordinates\n * Matches EVM keccak256(abi.encode(publicKeyX, publicKeyY))\n */\n private computeKeyHash(publicKeyX: bigint, publicKeyY: bigint): string {\n // Write as big-endian to match EVM encoding\n const xHex = publicKeyX.toString(16).padStart(64, '0');\n const yHex = publicKeyY.toString(16).padStart(64, '0');\n\n const xBytes = this.hexToBytes(xHex);\n const yBytes = this.hexToBytes(yHex);\n\n // Use SHA3-256 for Aptos (which is what Aptos uses natively)\n // For cross-chain compatibility, this should match the EVM hash\n const combined = new Uint8Array([...xBytes, ...yBytes]);\n const hash = sha3_256(combined);\n\n return '0x' + hash;\n }\n\n /**\n * Build message for signing (matches Hub chain format)\n */\n private buildMessage(\n keyHash: string,\n targetChain: number,\n actionPayload: string,\n nonce: bigint\n ): string {\n const keyHashBytes = this.hexToBytes(keyHash.replace('0x', ''));\n const targetChainBytes = new Uint8Array(2);\n targetChainBytes[0] = (targetChain >> 8) & 0xFF;\n targetChainBytes[1] = targetChain & 0xFF;\n const payloadBytes = this.hexToBytes(actionPayload.replace('0x', ''));\n const nonceHex = nonce.toString(16).padStart(64, '0');\n const nonceBytes = this.hexToBytes(nonceHex);\n\n const combined = new Uint8Array([\n ...keyHashBytes,\n ...targetChainBytes,\n ...payloadBytes,\n ...nonceBytes,\n ]);\n\n const hash = sha3_256(combined);\n return '0x' + hash;\n }\n\n /**\n * Get Aptos client instance for advanced usage\n */\n getClient(): Aptos {\n return this.client;\n }\n\n /**\n * Get module address\n */\n getModuleAddress(): string {\n return this.moduleAddress;\n }\n\n /**\n * Get current ledger version\n */\n async getLedgerVersion(): Promise<bigint> {\n const ledgerInfo = await this.client.getLedgerInfo();\n return BigInt(ledgerInfo.ledger_version);\n }\n\n /**\n * Get transaction by hash\n */\n async getTransaction(txHash: string): Promise<any> {\n return await this.client.getTransactionByHash({ transactionHash: txHash });\n }\n\n /**\n * Wait for transaction confirmation\n */\n async waitForTransaction(txHash: string, timeoutSecs: number = 30): Promise<any> {\n return await this.client.waitForTransaction({\n transactionHash: txHash,\n options: {\n timeoutSecs,\n checkSuccess: true,\n }\n });\n }\n\n // ============================================================================\n // Social Recovery Methods (Issue #23)\n // ============================================================================\n // \n // Note: Social recovery is managed on the Hub chain (EVM).\n // Aptos spokes receive and execute recovery VAAs broadcast from the Hub.\n // The relayer service handles submitting recovery transactions to Aptos.\n //\n // SDK users should use EVMClient methods for guardian management and\n // recovery initiation on the Hub chain.\n // ============================================================================\n\n /**\n * Get vault resource for an owner\n * \n * @param ownerKeyHash - Owner's passkey hash (32 bytes as hex)\n * @returns Vault resource data or null if not found\n */\n async getVaultResource(ownerKeyHash: string): Promise<{\n ownerKeyHash: string;\n authorizedSigners: string[];\n nonce: bigint;\n } | null> {\n try {\n const vaultAddress = this.computeVaultAddressFromHash(ownerKeyHash);\n\n const resource = await this.client.getAccountResource({\n accountAddress: vaultAddress,\n resourceType: `${this.moduleAddress}::vault::Vault`\n });\n\n if (!resource || !resource.data) {\n return null;\n }\n\n const data = resource.data as any;\n return {\n ownerKeyHash: data.owner_key_hash || ownerKeyHash,\n authorizedSigners: data.authorized_signers || [],\n nonce: BigInt(data.nonce || 0),\n };\n } catch (error) {\n console.error('Error getting vault resource:', error);\n return null;\n }\n }\n\n /**\n * Get authorized signers for a vault\n * \n * @param ownerKeyHash - Owner's passkey hash (32 bytes as hex)\n * @returns Array of authorized signer key hashes\n */\n async getAuthorizedSigners(ownerKeyHash: string): Promise<string[]> {\n const vaultResource = await this.getVaultResource(ownerKeyHash);\n return vaultResource?.authorizedSigners || [];\n }\n\n /**\n * Check if a VAA has been processed (for replay protection)\n * \n * @param vaaHash - VAA hash as hex string\n * @returns Whether the VAA has been processed\n */\n async isVaaProcessed(vaaHash: string): Promise<boolean> {\n try {\n const resource = await this.client.getAccountResource({\n accountAddress: this.moduleAddress,\n resourceType: `${this.moduleAddress}::spoke::ProcessedVAAs`\n });\n\n if (!resource || !resource.data) {\n return false;\n }\n\n const data = resource.data as any;\n const processedVaas = data.processed || [];\n\n // Check if vaaHash is in the processed list\n const normalizedHash = vaaHash.toLowerCase().replace('0x', '');\n return processedVaas.some((hash: string) => \n hash.toLowerCase().replace('0x', '') === normalizedHash\n );\n } catch (error) {\n console.error('Error checking VAA status:', error);\n return false;\n }\n }\n\n /**\n * Check if protocol is paused\n * \n * @returns Whether the protocol is paused\n */\n async isProtocolPaused(): Promise<boolean> {\n try {\n const resource = await this.client.getAccountResource({\n accountAddress: this.moduleAddress,\n resourceType: `${this.moduleAddress}::spoke::Config`\n });\n\n if (!resource || !resource.data) {\n return false;\n }\n\n const data = resource.data as any;\n return data.paused === true;\n } catch (error) {\n console.error('Error checking pause status:', error);\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import {
|
|
2
|
+
encodeBridgeAction,
|
|
3
|
+
encodeExecuteAction,
|
|
4
|
+
encodeTransferAction
|
|
5
|
+
} from "./chunk-F3YAGZSW.mjs";
|
|
6
|
+
|
|
7
|
+
// src/chains/sui/SuiClient.ts
|
|
8
|
+
import { SuiClient as MystenSuiClient } from "@mysten/sui/client";
|
|
9
|
+
import { createHash } from "crypto";
|
|
10
|
+
var SuiClient = class {
|
|
11
|
+
config;
|
|
12
|
+
client;
|
|
13
|
+
packageId;
|
|
14
|
+
hubRpcUrl;
|
|
15
|
+
hubContractAddress;
|
|
16
|
+
constructor(config) {
|
|
17
|
+
this.config = {
|
|
18
|
+
name: `Sui ${config.network || "mainnet"}`,
|
|
19
|
+
chainId: 0,
|
|
20
|
+
wormholeChainId: config.wormholeChainId,
|
|
21
|
+
rpcUrl: config.rpcUrl,
|
|
22
|
+
explorerUrl: config.network === "testnet" ? "https://suiscan.xyz/testnet" : config.network === "devnet" ? "https://suiscan.xyz/devnet" : "https://suiscan.xyz/mainnet",
|
|
23
|
+
isEvm: false,
|
|
24
|
+
contracts: {
|
|
25
|
+
hub: config.packageId,
|
|
26
|
+
wormholeCoreBridge: config.wormholeCoreBridge,
|
|
27
|
+
tokenBridge: config.tokenBridge
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
this.client = new MystenSuiClient({ url: config.rpcUrl });
|
|
31
|
+
this.packageId = config.packageId;
|
|
32
|
+
this.hubRpcUrl = config.hubRpcUrl;
|
|
33
|
+
this.hubContractAddress = config.hubContractAddress;
|
|
34
|
+
}
|
|
35
|
+
getConfig() {
|
|
36
|
+
return this.config;
|
|
37
|
+
}
|
|
38
|
+
async getNonce(_userKeyHash) {
|
|
39
|
+
return 0n;
|
|
40
|
+
}
|
|
41
|
+
async getMessageFee() {
|
|
42
|
+
return 0n;
|
|
43
|
+
}
|
|
44
|
+
async buildTransferPayload(params) {
|
|
45
|
+
return encodeTransferAction(params.token, params.recipient, params.amount);
|
|
46
|
+
}
|
|
47
|
+
async buildExecutePayload(params) {
|
|
48
|
+
return encodeExecuteAction(params.target, params.value, params.data);
|
|
49
|
+
}
|
|
50
|
+
async buildBridgePayload(params) {
|
|
51
|
+
return encodeBridgeAction(params.token, params.amount, params.destinationChain, params.recipient);
|
|
52
|
+
}
|
|
53
|
+
async dispatch(signature, publicKeyX, publicKeyY, targetChain, actionPayload, nonce, signer) {
|
|
54
|
+
void signature;
|
|
55
|
+
void publicKeyX;
|
|
56
|
+
void publicKeyY;
|
|
57
|
+
void targetChain;
|
|
58
|
+
void actionPayload;
|
|
59
|
+
void nonce;
|
|
60
|
+
void signer;
|
|
61
|
+
throw new Error(
|
|
62
|
+
"Direct dispatch not supported on Sui spoke chains. Actions must be dispatched from the Hub (EVM) chain. "
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
async dispatchGasless(signature, publicKeyX, publicKeyY, targetChain, actionPayload, nonce, relayerUrl) {
|
|
66
|
+
const keyHash = this.computeKeyHash(publicKeyX, publicKeyY);
|
|
67
|
+
const messageHash = this.buildMessageHash(keyHash, targetChain, actionPayload, nonce);
|
|
68
|
+
const request = {
|
|
69
|
+
messageHash,
|
|
70
|
+
r: "0x" + signature.r.toString(16).padStart(64, "0"),
|
|
71
|
+
s: "0x" + signature.s.toString(16).padStart(64, "0"),
|
|
72
|
+
publicKeyX: "0x" + publicKeyX.toString(16).padStart(64, "0"),
|
|
73
|
+
publicKeyY: "0x" + publicKeyY.toString(16).padStart(64, "0"),
|
|
74
|
+
targetChain,
|
|
75
|
+
actionPayload,
|
|
76
|
+
nonce: Number(nonce)
|
|
77
|
+
};
|
|
78
|
+
const response = await fetch(`${relayerUrl}/api/v1/submit`, {
|
|
79
|
+
method: "POST",
|
|
80
|
+
headers: { "Content-Type": "application/json" },
|
|
81
|
+
body: JSON.stringify(request)
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
throw new Error(`Relayer submission failed: ${response.status} ${response.statusText}`);
|
|
85
|
+
}
|
|
86
|
+
const result = await response.json();
|
|
87
|
+
return {
|
|
88
|
+
transactionHash: result.transactionHash ?? result.txHash,
|
|
89
|
+
sequence: BigInt(result.sequence || 0),
|
|
90
|
+
userKeyHash: keyHash,
|
|
91
|
+
targetChain
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async getVaultAddress(userKeyHash) {
|
|
95
|
+
return this.computeVaultAddress(userKeyHash);
|
|
96
|
+
}
|
|
97
|
+
computeVaultAddress(userKeyHash) {
|
|
98
|
+
const clean = userKeyHash.replace(/^0x/, "").padStart(64, "0");
|
|
99
|
+
return "0x" + clean;
|
|
100
|
+
}
|
|
101
|
+
async vaultExists(_userKeyHash) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
async createVault(userKeyHash, signer) {
|
|
105
|
+
void signer;
|
|
106
|
+
throw new Error(
|
|
107
|
+
`Vault creation on Sui must be done via cross-chain message from Hub. Use the Hub client to dispatch a vault creation action targeting Sui (chain ${this.config.wormholeChainId}). KeyHash=${userKeyHash}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
async createVaultSponsored(userKeyHash, sponsorPrivateKey, rpcUrl) {
|
|
111
|
+
void userKeyHash;
|
|
112
|
+
void sponsorPrivateKey;
|
|
113
|
+
void rpcUrl;
|
|
114
|
+
throw new Error(
|
|
115
|
+
"Vault creation on Sui must be done via cross-chain message from Hub. Use relayer gasless submission to create vault."
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Create a vault via the relayer (sponsored/gasless)
|
|
120
|
+
* This is the recommended way to create Sui vaults
|
|
121
|
+
*
|
|
122
|
+
* The relayer will dispatch a vault creation action from Hub to Sui spoke
|
|
123
|
+
*/
|
|
124
|
+
async createVaultViaRelayer(userKeyHash, relayerUrl) {
|
|
125
|
+
const response = await fetch(`${relayerUrl}/api/v1/sui/vault`, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
headers: {
|
|
128
|
+
"Content-Type": "application/json"
|
|
129
|
+
},
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
userKeyHash,
|
|
132
|
+
chainId: this.config.wormholeChainId
|
|
133
|
+
})
|
|
134
|
+
});
|
|
135
|
+
const result = await response.json();
|
|
136
|
+
if (!response.ok || !result.success) {
|
|
137
|
+
throw new Error(result.error || "Failed to create vault via relayer");
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
address: result.vaultAddress,
|
|
141
|
+
transactionHash: result.transactionHash || "",
|
|
142
|
+
blockNumber: 0,
|
|
143
|
+
gasUsed: 0n,
|
|
144
|
+
alreadyExisted: result.alreadyExists || false,
|
|
145
|
+
sponsoredBy: "relayer"
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get vault info via relayer (includes existence check)
|
|
150
|
+
*/
|
|
151
|
+
async getVaultViaRelayer(userKeyHash, relayerUrl) {
|
|
152
|
+
const response = await fetch(
|
|
153
|
+
`${relayerUrl}/api/v1/sui/vault/${userKeyHash}?chainId=${this.config.wormholeChainId}`
|
|
154
|
+
);
|
|
155
|
+
if (!response.ok) {
|
|
156
|
+
throw new Error("Failed to get vault info from relayer");
|
|
157
|
+
}
|
|
158
|
+
const result = await response.json();
|
|
159
|
+
return {
|
|
160
|
+
vaultAddress: result.vaultAddress,
|
|
161
|
+
exists: result.exists
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async estimateVaultCreationGas(_userKeyHash) {
|
|
165
|
+
return 5000n;
|
|
166
|
+
}
|
|
167
|
+
getFactoryAddress() {
|
|
168
|
+
return void 0;
|
|
169
|
+
}
|
|
170
|
+
getImplementationAddress() {
|
|
171
|
+
return void 0;
|
|
172
|
+
}
|
|
173
|
+
// ========================================================================
|
|
174
|
+
// Balance utilities (used by VeridexSDK multichain)
|
|
175
|
+
// ========================================================================
|
|
176
|
+
async getNativeBalance(address) {
|
|
177
|
+
const balance = await this.client.getBalance({ owner: address });
|
|
178
|
+
return BigInt(balance.totalBalance);
|
|
179
|
+
}
|
|
180
|
+
async getTokenBalance(coinType, ownerAddress) {
|
|
181
|
+
const balance = await this.client.getBalance({ owner: ownerAddress, coinType });
|
|
182
|
+
return BigInt(balance.totalBalance);
|
|
183
|
+
}
|
|
184
|
+
getClient() {
|
|
185
|
+
return this.client;
|
|
186
|
+
}
|
|
187
|
+
getPackageId() {
|
|
188
|
+
return this.packageId;
|
|
189
|
+
}
|
|
190
|
+
// ========================================================================
|
|
191
|
+
// Session Management (Issue #13)
|
|
192
|
+
// ========================================================================
|
|
193
|
+
/**
|
|
194
|
+
* Register a session key on the Hub (must be called via Hub client)
|
|
195
|
+
* Sui spokes validate sessions via CCQ, but registration happens on Hub
|
|
196
|
+
*
|
|
197
|
+
* @throws Error - Session management must be done via Hub chain
|
|
198
|
+
*/
|
|
199
|
+
async registerSession(_params) {
|
|
200
|
+
throw new Error(
|
|
201
|
+
"Session registration must be performed on the Hub chain (Base). Use EVMClient connected to the Hub to call registerSession()."
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Revoke a session key on the Hub (must be called via Hub client)
|
|
206
|
+
*
|
|
207
|
+
* @throws Error - Session management must be done via Hub chain
|
|
208
|
+
*/
|
|
209
|
+
async revokeSession(_params) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
"Session revocation must be performed on the Hub chain (Base). Use EVMClient connected to the Hub to call revokeSession()."
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check if a session is active by querying the Hub
|
|
216
|
+
* This method queries the Hub contract directly for session validation
|
|
217
|
+
*
|
|
218
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
219
|
+
* @param sessionKeyHash - Hash of session key to validate
|
|
220
|
+
* @returns Session validation result with expiry and limits
|
|
221
|
+
*/
|
|
222
|
+
async isSessionActive(_userKeyHash, _sessionKeyHash) {
|
|
223
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
224
|
+
throw new Error(
|
|
225
|
+
"Hub configuration required for session validation. Provide hubRpcUrl and hubContractAddress in SuiClientConfig."
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
throw new Error(
|
|
229
|
+
"isSessionActive requires Hub client integration. Use EVMClient.isSessionActive() on the Hub chain, then pass the result to session execution on Sui."
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get all sessions for a user from the Hub
|
|
234
|
+
*
|
|
235
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
236
|
+
* @returns Array of all sessions (active and expired/revoked)
|
|
237
|
+
*/
|
|
238
|
+
async getUserSessions(userKeyHash) {
|
|
239
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
"Hub configuration required for session queries. Provide hubRpcUrl and hubContractAddress in SuiClientConfig."
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
throw new Error(
|
|
245
|
+
`getUserSessions requires Hub client integration. Use EVMClient.getUserSessions() on the Hub chain. User: ${userKeyHash}`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
// ========================================================================
|
|
249
|
+
// Query-Based Execution (Issue #9/#10)
|
|
250
|
+
// ========================================================================
|
|
251
|
+
/**
|
|
252
|
+
* Get user state from Hub (comprehensive state query)
|
|
253
|
+
* Returns key hash, nonce, and last action hash for CCQ validation
|
|
254
|
+
*
|
|
255
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
256
|
+
* @returns User state with nonce and last action hash
|
|
257
|
+
*/
|
|
258
|
+
async getUserState(userKeyHash) {
|
|
259
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
"Hub configuration required for state queries. Provide hubRpcUrl and hubContractAddress in SuiClientConfig."
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
throw new Error(
|
|
265
|
+
`getUserState requires Hub client integration. Use EVMClient.getUserState() on the Hub chain. User: ${userKeyHash}`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get user's last action hash from Hub
|
|
270
|
+
* Used for optimistic execution and nonce validation
|
|
271
|
+
*
|
|
272
|
+
* @param userKeyHash - Hash of user's Passkey public key
|
|
273
|
+
* @returns Last action hash (zero hash if no actions)
|
|
274
|
+
*/
|
|
275
|
+
async getUserLastActionHash(userKeyHash) {
|
|
276
|
+
if (!this.hubRpcUrl || !this.hubContractAddress) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
"Hub configuration required for action hash queries. Provide hubRpcUrl and hubContractAddress in SuiClientConfig."
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
throw new Error(
|
|
282
|
+
`getUserLastActionHash requires Hub client integration. Use EVMClient.getUserLastActionHash() on the Hub chain. User: ${userKeyHash}`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Execute with query-based validation (faster than VAA, ~23s vs 60-90s)
|
|
287
|
+
* Uses Wormhole CCQ to validate Hub state, then executes on Sui
|
|
288
|
+
*
|
|
289
|
+
* @param params Query execution parameters with CCQ response
|
|
290
|
+
* @returns Dispatch result with transaction hash
|
|
291
|
+
*
|
|
292
|
+
* @remarks
|
|
293
|
+
* Query-based execution flow:
|
|
294
|
+
* 1. Query Hub state via Wormhole CCQ
|
|
295
|
+
* 2. Validate Guardian signatures on query response
|
|
296
|
+
* 3. Execute on Sui with validated state
|
|
297
|
+
* 4. Hub state must be < 60s stale (enforced by QueryVerifier)
|
|
298
|
+
*/
|
|
299
|
+
async executeWithQuery(_params) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
"Query-based execution on Sui requires relayer integration. Use relayer API to submit query-validated transactions. Relayer will call veridex_spoke::execute_with_query on Sui."
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
// ========================================================================
|
|
305
|
+
// Internal helpers
|
|
306
|
+
// ========================================================================
|
|
307
|
+
computeKeyHash(publicKeyX, publicKeyY) {
|
|
308
|
+
const xHex = publicKeyX.toString(16).padStart(64, "0");
|
|
309
|
+
const yHex = publicKeyY.toString(16).padStart(64, "0");
|
|
310
|
+
const combined = Buffer.from(xHex + yHex, "hex");
|
|
311
|
+
const hash = createHash("sha256").update(combined).digest("hex");
|
|
312
|
+
return "0x" + hash;
|
|
313
|
+
}
|
|
314
|
+
buildMessageHash(keyHash, targetChain, actionPayload, nonce) {
|
|
315
|
+
const keyHashBuffer = Buffer.from(keyHash.replace(/^0x/, ""), "hex");
|
|
316
|
+
const targetChainBuffer = Buffer.alloc(2);
|
|
317
|
+
targetChainBuffer.writeUInt16BE(targetChain);
|
|
318
|
+
const payloadBuffer = Buffer.from(actionPayload.replace(/^0x/, ""), "hex");
|
|
319
|
+
const nonceHex = nonce.toString(16).padStart(64, "0");
|
|
320
|
+
const nonceBuffer = Buffer.from(nonceHex, "hex");
|
|
321
|
+
const combined = Buffer.concat([keyHashBuffer, targetChainBuffer, payloadBuffer, nonceBuffer]);
|
|
322
|
+
const hash = createHash("sha256").update(combined).digest("hex");
|
|
323
|
+
return "0x" + hash;
|
|
324
|
+
}
|
|
325
|
+
// ============================================================================
|
|
326
|
+
// Social Recovery Methods (Issue #23)
|
|
327
|
+
// ============================================================================
|
|
328
|
+
//
|
|
329
|
+
// Note: Social recovery is managed on the Hub chain (EVM).
|
|
330
|
+
// Sui spokes receive and execute recovery VAAs broadcast from the Hub.
|
|
331
|
+
// The relayer service handles submitting recovery transactions to Sui.
|
|
332
|
+
//
|
|
333
|
+
// SDK users should use EVMClient methods for guardian management and
|
|
334
|
+
// recovery initiation on the Hub chain.
|
|
335
|
+
// ============================================================================
|
|
336
|
+
/**
|
|
337
|
+
* Get vault object ID by owner key hash
|
|
338
|
+
*
|
|
339
|
+
* @param ownerKeyHash - Owner's passkey hash (32 bytes as hex)
|
|
340
|
+
* @param configObjectId - Shared Config object ID
|
|
341
|
+
* @param registryObjectId - Shared VaultRegistry object ID
|
|
342
|
+
* @returns Vault object ID or null if not found
|
|
343
|
+
*/
|
|
344
|
+
async getVaultId(_ownerKeyHash, registryObjectId) {
|
|
345
|
+
try {
|
|
346
|
+
const registryObject = await this.client.getObject({
|
|
347
|
+
id: registryObjectId,
|
|
348
|
+
options: { showContent: true }
|
|
349
|
+
});
|
|
350
|
+
if (!registryObject.data?.content) {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
console.warn("getVaultId requires dynamic field query - use Move view function");
|
|
354
|
+
return null;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error("Error getting vault ID:", error);
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Get vault owner key hash from vault object
|
|
362
|
+
*
|
|
363
|
+
* @param vaultObjectId - Vault object ID
|
|
364
|
+
* @returns Owner key hash as hex string
|
|
365
|
+
*/
|
|
366
|
+
async getVaultOwner(vaultObjectId) {
|
|
367
|
+
try {
|
|
368
|
+
const vaultObject = await this.client.getObject({
|
|
369
|
+
id: vaultObjectId,
|
|
370
|
+
options: { showContent: true }
|
|
371
|
+
});
|
|
372
|
+
if (!vaultObject.data?.content || vaultObject.data.content.dataType !== "moveObject") {
|
|
373
|
+
return null;
|
|
374
|
+
}
|
|
375
|
+
const fields = vaultObject.data.content.fields;
|
|
376
|
+
const ownerKeyHash = fields["owner_key_hash"];
|
|
377
|
+
if (!ownerKeyHash) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
return "0x" + Buffer.from(ownerKeyHash).toString("hex");
|
|
381
|
+
} catch (error) {
|
|
382
|
+
console.error("Error getting vault owner:", error);
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get authorized signers for a vault
|
|
388
|
+
*
|
|
389
|
+
* @param vaultObjectId - Vault object ID
|
|
390
|
+
* @returns Array of authorized signer key hashes
|
|
391
|
+
*/
|
|
392
|
+
async getAuthorizedSigners(vaultObjectId) {
|
|
393
|
+
try {
|
|
394
|
+
const vaultObject = await this.client.getObject({
|
|
395
|
+
id: vaultObjectId,
|
|
396
|
+
options: { showContent: true }
|
|
397
|
+
});
|
|
398
|
+
if (!vaultObject.data?.content || vaultObject.data.content.dataType !== "moveObject") {
|
|
399
|
+
return [];
|
|
400
|
+
}
|
|
401
|
+
const fields = vaultObject.data.content.fields;
|
|
402
|
+
const authorizedSigners = fields["authorized_signers"];
|
|
403
|
+
if (!authorizedSigners) {
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
return authorizedSigners.map(
|
|
407
|
+
(signer) => "0x" + Buffer.from(signer).toString("hex")
|
|
408
|
+
);
|
|
409
|
+
} catch (error) {
|
|
410
|
+
console.error("Error getting authorized signers:", error);
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Check if a VAA has been processed (for replay protection)
|
|
416
|
+
*
|
|
417
|
+
* @param vaaHash - VAA hash as hex string
|
|
418
|
+
* @param processedVaasObjectId - ProcessedVAAs shared object ID
|
|
419
|
+
* @returns Whether the VAA has been processed
|
|
420
|
+
*/
|
|
421
|
+
async isVaaProcessed(_vaaHash, processedVaasObjectId) {
|
|
422
|
+
try {
|
|
423
|
+
const processedObject = await this.client.getObject({
|
|
424
|
+
id: processedVaasObjectId,
|
|
425
|
+
options: { showContent: true }
|
|
426
|
+
});
|
|
427
|
+
if (!processedObject.data?.content) {
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
console.warn("isVaaProcessed requires dynamic field query");
|
|
431
|
+
return false;
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.error("Error checking VAA status:", error);
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Check if protocol is paused
|
|
439
|
+
*
|
|
440
|
+
* @param configObjectId - Config shared object ID
|
|
441
|
+
* @returns Whether the protocol is paused
|
|
442
|
+
*/
|
|
443
|
+
async isProtocolPaused(configObjectId) {
|
|
444
|
+
try {
|
|
445
|
+
const configObject = await this.client.getObject({
|
|
446
|
+
id: configObjectId,
|
|
447
|
+
options: { showContent: true }
|
|
448
|
+
});
|
|
449
|
+
if (!configObject.data?.content || configObject.data.content.dataType !== "moveObject") {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
const fields = configObject.data.content.fields;
|
|
453
|
+
return fields["paused"] === true;
|
|
454
|
+
} catch (error) {
|
|
455
|
+
console.error("Error checking pause status:", error);
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
export {
|
|
462
|
+
SuiClient
|
|
463
|
+
};
|
|
464
|
+
//# sourceMappingURL=chunk-SXXGTQIR.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chains/sui/SuiClient.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Sui Chain Client\n *\n * Production-grade implementation of ChainClient interface for Sui.\n * Supports session management, query-based execution, and vault operations.\n *\n * Security:\n * - Native sui::ecdsa_k1::secp256k1_verify for signature validation\n * - CCQ-based session validation with 60s staleness window\n * - Replay protection via nonce verification\n *\n * Note: Sui is a spoke chain. Session registration/revocation happens on Hub.\n */\n\nimport { SuiClient as MystenSuiClient } from '@mysten/sui/client';\nimport { createHash } from 'crypto';\nimport type { SessionKey } from '../../sessions/types.js';\nimport type {\n ChainClient,\n ChainConfig,\n TransferParams,\n ExecuteParams,\n BridgeParams,\n DispatchResult,\n WebAuthnSignature,\n VaultCreationResult,\n RegisterSessionParams,\n RevokeSessionParams,\n SessionValidationResult,\n} from '../../core/types.js';\nimport { encodeTransferAction, encodeExecuteAction, encodeBridgeAction } from '../../payload.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface SuiClientConfig {\n wormholeChainId: number;\n rpcUrl: string;\n packageId: string; // Veridex Spoke package ID\n wormholeCoreBridge: string;\n tokenBridge?: string;\n network?: 'mainnet' | 'testnet' | 'devnet';\n hubRpcUrl?: string; // Hub chain RPC for session management\n hubContractAddress?: string; // Hub contract for session management\n}\n\n// ============================================================================\n// SuiClient\n// ============================================================================\n\nexport class SuiClient implements ChainClient {\n private config: ChainConfig;\n private client: MystenSuiClient;\n private packageId: string;\n private hubRpcUrl?: string;\n private hubContractAddress?: string;\n\n constructor(config: SuiClientConfig) {\n this.config = {\n name: `Sui ${config.network || 'mainnet'}`,\n chainId: 0,\n wormholeChainId: config.wormholeChainId,\n rpcUrl: config.rpcUrl,\n explorerUrl: config.network === 'testnet'\n ? 'https://suiscan.xyz/testnet'\n : config.network === 'devnet'\n ? 'https://suiscan.xyz/devnet'\n : 'https://suiscan.xyz/mainnet',\n isEvm: false,\n contracts: {\n hub: config.packageId,\n wormholeCoreBridge: config.wormholeCoreBridge,\n tokenBridge: config.tokenBridge,\n },\n };\n\n this.client = new MystenSuiClient({ url: config.rpcUrl });\n this.packageId = config.packageId;\n this.hubRpcUrl = config.hubRpcUrl;\n this.hubContractAddress = config.hubContractAddress;\n }\n\n getConfig(): ChainConfig {\n return this.config;\n }\n\n async getNonce(_userKeyHash: string): Promise<bigint> {\n // Nonce is managed on the Hub for cross-chain actions.\n return 0n;\n }\n\n async getMessageFee(): Promise<bigint> {\n // Wormhole fees for Sui are generally handled by relayer submission.\n return 0n;\n }\n\n async buildTransferPayload(params: TransferParams): Promise<string> {\n return encodeTransferAction(params.token, params.recipient, params.amount);\n }\n\n async buildExecutePayload(params: ExecuteParams): Promise<string> {\n return encodeExecuteAction(params.target, params.value, params.data);\n }\n\n async buildBridgePayload(params: BridgeParams): Promise<string> {\n return encodeBridgeAction(params.token, params.amount, params.destinationChain, params.recipient);\n }\n\n async dispatch(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n signer: any\n ): Promise<DispatchResult> {\n void signature;\n void publicKeyX;\n void publicKeyY;\n void targetChain;\n void actionPayload;\n void nonce;\n void signer;\n throw new Error(\n 'Direct dispatch not supported on Sui spoke chains. ' +\n 'Actions must be dispatched from the Hub (EVM) chain. '\n );\n }\n\n async dispatchGasless(\n signature: WebAuthnSignature,\n publicKeyX: bigint,\n publicKeyY: bigint,\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n relayerUrl: string\n ): Promise<DispatchResult> {\n const keyHash = this.computeKeyHash(publicKeyX, publicKeyY);\n const messageHash = this.buildMessageHash(keyHash, targetChain, actionPayload, nonce);\n\n const request = {\n messageHash,\n r: '0x' + signature.r.toString(16).padStart(64, '0'),\n s: '0x' + signature.s.toString(16).padStart(64, '0'),\n publicKeyX: '0x' + publicKeyX.toString(16).padStart(64, '0'),\n publicKeyY: '0x' + publicKeyY.toString(16).padStart(64, '0'),\n targetChain,\n actionPayload,\n nonce: Number(nonce),\n };\n\n const response = await fetch(`${relayerUrl}/api/v1/submit`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`Relayer submission failed: ${response.status} ${response.statusText}`);\n }\n\n const result = await response.json();\n\n return {\n transactionHash: result.transactionHash ?? result.txHash,\n sequence: BigInt(result.sequence || 0),\n userKeyHash: keyHash,\n targetChain,\n };\n }\n\n async getVaultAddress(userKeyHash: string): Promise<string | null> {\n // Sui vaults may be represented as shared objects on-chain; without registry object IDs,\n // we return the deterministic address used by the SDK for receiving and balance display.\n return this.computeVaultAddress(userKeyHash);\n }\n\n computeVaultAddress(userKeyHash: string): string {\n // SDK convention: Sui addresses are 32-byte hex with 0x prefix.\n const clean = userKeyHash.replace(/^0x/, '').padStart(64, '0');\n return '0x' + clean;\n }\n\n async vaultExists(_userKeyHash: string): Promise<boolean> {\n // Account addresses on Sui are implicit; treat as existing.\n return true;\n }\n\n async createVault(userKeyHash: string, signer: any): Promise<VaultCreationResult> {\n void signer;\n throw new Error(\n 'Vault creation on Sui must be done via cross-chain message from Hub. ' +\n `Use the Hub client to dispatch a vault creation action targeting Sui (chain ${this.config.wormholeChainId}). KeyHash=${userKeyHash}`\n );\n }\n\n async createVaultSponsored?(userKeyHash: string, sponsorPrivateKey: string, rpcUrl?: string): Promise<VaultCreationResult> {\n void userKeyHash;\n void sponsorPrivateKey;\n void rpcUrl;\n throw new Error(\n 'Vault creation on Sui must be done via cross-chain message from Hub. ' +\n 'Use relayer gasless submission to create vault.'\n );\n }\n\n /**\n * Create a vault via the relayer (sponsored/gasless)\n * This is the recommended way to create Sui vaults\n * \n * The relayer will dispatch a vault creation action from Hub to Sui spoke\n */\n async createVaultViaRelayer(\n userKeyHash: string,\n relayerUrl: string\n ): Promise<VaultCreationResult> {\n const response = await fetch(`${relayerUrl}/api/v1/sui/vault`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n userKeyHash,\n chainId: this.config.wormholeChainId,\n }),\n });\n\n const result = await response.json();\n\n if (!response.ok || !result.success) {\n throw new Error(result.error || 'Failed to create vault via relayer');\n }\n\n return {\n address: result.vaultAddress,\n transactionHash: result.transactionHash || '',\n blockNumber: 0,\n gasUsed: 0n,\n alreadyExisted: result.alreadyExists || false,\n sponsoredBy: 'relayer',\n };\n }\n\n /**\n * Get vault info via relayer (includes existence check)\n */\n async getVaultViaRelayer(\n userKeyHash: string,\n relayerUrl: string\n ): Promise<{ vaultAddress: string; exists: boolean }> {\n const response = await fetch(\n `${relayerUrl}/api/v1/sui/vault/${userKeyHash}?chainId=${this.config.wormholeChainId}`\n );\n\n if (!response.ok) {\n throw new Error('Failed to get vault info from relayer');\n }\n\n const result = await response.json();\n return {\n vaultAddress: result.vaultAddress,\n exists: result.exists,\n };\n }\n\n async estimateVaultCreationGas(_userKeyHash: string): Promise<bigint> {\n // Best-effort placeholder.\n return 5_000n;\n }\n\n getFactoryAddress(): string | undefined {\n return undefined;\n }\n\n getImplementationAddress(): string | undefined {\n return undefined;\n }\n\n // ========================================================================\n // Balance utilities (used by VeridexSDK multichain)\n // ========================================================================\n\n async getNativeBalance(address: string): Promise<bigint> {\n const balance = await this.client.getBalance({ owner: address });\n return BigInt(balance.totalBalance);\n }\n\n async getTokenBalance(coinType: string, ownerAddress: string): Promise<bigint> {\n const balance = await this.client.getBalance({ owner: ownerAddress, coinType });\n return BigInt(balance.totalBalance);\n }\n\n getClient(): MystenSuiClient {\n return this.client;\n }\n\n getPackageId(): string {\n return this.packageId;\n }\n\n // ========================================================================\n // Session Management (Issue #13)\n // ========================================================================\n\n /**\n * Register a session key on the Hub (must be called via Hub client)\n * Sui spokes validate sessions via CCQ, but registration happens on Hub\n * \n * @throws Error - Session management must be done via Hub chain\n */\n async registerSession(_params: RegisterSessionParams): Promise<void> {\n throw new Error(\n 'Session registration must be performed on the Hub chain (Base). ' +\n 'Use EVMClient connected to the Hub to call registerSession().'\n );\n }\n\n /**\n * Revoke a session key on the Hub (must be called via Hub client)\n * \n * @throws Error - Session management must be done via Hub chain\n */\n async revokeSession(_params: RevokeSessionParams): Promise<void> {\n throw new Error(\n 'Session revocation must be performed on the Hub chain (Base). ' +\n 'Use EVMClient connected to the Hub to call revokeSession().'\n );\n }\n\n /**\n * Check if a session is active by querying the Hub\n * This method queries the Hub contract directly for session validation\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @param sessionKeyHash - Hash of session key to validate\n * @returns Session validation result with expiry and limits\n */\n async isSessionActive(\n _userKeyHash: string,\n _sessionKeyHash: string\n ): Promise<SessionValidationResult> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for session validation. ' +\n 'Provide hubRpcUrl and hubContractAddress in SuiClientConfig.'\n );\n }\n\n // Query Hub contract for session status\n // This would normally use ethers.js to query the Hub contract\n // For production, import ethers dynamically or pass Hub client\n throw new Error(\n 'isSessionActive requires Hub client integration. ' +\n 'Use EVMClient.isSessionActive() on the Hub chain, ' +\n 'then pass the result to session execution on Sui.'\n );\n }\n\n /**\n * Get all sessions for a user from the Hub\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @returns Array of all sessions (active and expired/revoked)\n */\n async getUserSessions(userKeyHash: string): Promise<SessionKey[]> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for session queries. ' +\n 'Provide hubRpcUrl and hubContractAddress in SuiClientConfig.'\n );\n }\n\n // Query Hub contract for user sessions\n throw new Error(\n 'getUserSessions requires Hub client integration. ' +\n 'Use EVMClient.getUserSessions() on the Hub chain. ' +\n `User: ${userKeyHash}`\n );\n }\n\n // ========================================================================\n // Query-Based Execution (Issue #9/#10)\n // ========================================================================\n\n /**\n * Get user state from Hub (comprehensive state query)\n * Returns key hash, nonce, and last action hash for CCQ validation\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @returns User state with nonce and last action hash\n */\n async getUserState(userKeyHash: string): Promise<{\n keyHash: string;\n nonce: bigint;\n lastActionHash: string;\n }> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for state queries. ' +\n 'Provide hubRpcUrl and hubContractAddress in SuiClientConfig.'\n );\n }\n\n // Query Hub contract for user state\n // This enables query-based execution with CCQ validation\n throw new Error(\n 'getUserState requires Hub client integration. ' +\n 'Use EVMClient.getUserState() on the Hub chain. ' +\n `User: ${userKeyHash}`\n );\n }\n\n /**\n * Get user's last action hash from Hub\n * Used for optimistic execution and nonce validation\n * \n * @param userKeyHash - Hash of user's Passkey public key\n * @returns Last action hash (zero hash if no actions)\n */\n async getUserLastActionHash(userKeyHash: string): Promise<string> {\n if (!this.hubRpcUrl || !this.hubContractAddress) {\n throw new Error(\n 'Hub configuration required for action hash queries. ' +\n 'Provide hubRpcUrl and hubContractAddress in SuiClientConfig.'\n );\n }\n\n // Query Hub contract for last action hash\n throw new Error(\n 'getUserLastActionHash requires Hub client integration. ' +\n 'Use EVMClient.getUserLastActionHash() on the Hub chain. ' +\n `User: ${userKeyHash}`\n );\n }\n\n /**\n * Execute with query-based validation (faster than VAA, ~23s vs 60-90s)\n * Uses Wormhole CCQ to validate Hub state, then executes on Sui\n * \n * @param params Query execution parameters with CCQ response\n * @returns Dispatch result with transaction hash\n * \n * @remarks\n * Query-based execution flow:\n * 1. Query Hub state via Wormhole CCQ\n * 2. Validate Guardian signatures on query response\n * 3. Execute on Sui with validated state\n * 4. Hub state must be < 60s stale (enforced by QueryVerifier)\n */\n async executeWithQuery(\n _params: {\n userKeyHash: string;\n queryResponse: Uint8Array; // CCQ Guardian response\n actionType: number;\n actionPayload: Uint8Array;\n relayerUrl?: string;\n }\n ): Promise<DispatchResult> {\n throw new Error(\n 'Query-based execution on Sui requires relayer integration. ' +\n 'Use relayer API to submit query-validated transactions. ' +\n 'Relayer will call veridex_spoke::execute_with_query on Sui.'\n );\n }\n\n // ========================================================================\n // Internal helpers\n // ========================================================================\n\n private computeKeyHash(publicKeyX: bigint, publicKeyY: bigint): string {\n const xHex = publicKeyX.toString(16).padStart(64, '0');\n const yHex = publicKeyY.toString(16).padStart(64, '0');\n const combined = Buffer.from(xHex + yHex, 'hex');\n const hash = createHash('sha256').update(combined).digest('hex');\n return '0x' + hash;\n }\n\n private buildMessageHash(keyHash: string, targetChain: number, actionPayload: string, nonce: bigint): string {\n const keyHashBuffer = Buffer.from(keyHash.replace(/^0x/, ''), 'hex');\n const targetChainBuffer = Buffer.alloc(2);\n targetChainBuffer.writeUInt16BE(targetChain);\n const payloadBuffer = Buffer.from(actionPayload.replace(/^0x/, ''), 'hex');\n const nonceHex = nonce.toString(16).padStart(64, '0');\n const nonceBuffer = Buffer.from(nonceHex, 'hex');\n\n const combined = Buffer.concat([keyHashBuffer, targetChainBuffer, payloadBuffer, nonceBuffer]);\n const hash = createHash('sha256').update(combined).digest('hex');\n return '0x' + hash;\n }\n\n // ============================================================================\n // Social Recovery Methods (Issue #23)\n // ============================================================================\n // \n // Note: Social recovery is managed on the Hub chain (EVM).\n // Sui spokes receive and execute recovery VAAs broadcast from the Hub.\n // The relayer service handles submitting recovery transactions to Sui.\n //\n // SDK users should use EVMClient methods for guardian management and\n // recovery initiation on the Hub chain.\n // ============================================================================\n\n /**\n * Get vault object ID by owner key hash\n * \n * @param ownerKeyHash - Owner's passkey hash (32 bytes as hex)\n * @param configObjectId - Shared Config object ID\n * @param registryObjectId - Shared VaultRegistry object ID\n * @returns Vault object ID or null if not found\n */\n async getVaultId(\n _ownerKeyHash: string,\n registryObjectId: string\n ): Promise<string | null> {\n try {\n // Query the VaultRegistry table for the owner_key_hash\n // The registry maps owner_key_hash -> vault ID\n const registryObject = await this.client.getObject({\n id: registryObjectId,\n options: { showContent: true },\n });\n\n if (!registryObject.data?.content) {\n return null;\n }\n\n // For a proper implementation, we'd need to query dynamic fields\n // or use a Move view function. This is a placeholder showing the pattern.\n console.warn('getVaultId requires dynamic field query - use Move view function');\n return null;\n } catch (error) {\n console.error('Error getting vault ID:', error);\n return null;\n }\n }\n\n /**\n * Get vault owner key hash from vault object\n * \n * @param vaultObjectId - Vault object ID\n * @returns Owner key hash as hex string\n */\n async getVaultOwner(vaultObjectId: string): Promise<string | null> {\n try {\n const vaultObject = await this.client.getObject({\n id: vaultObjectId,\n options: { showContent: true },\n });\n\n if (!vaultObject.data?.content || vaultObject.data.content.dataType !== 'moveObject') {\n return null;\n }\n\n const fields = vaultObject.data.content.fields as Record<string, unknown>;\n const ownerKeyHash = fields['owner_key_hash'] as number[] | undefined;\n\n if (!ownerKeyHash) {\n return null;\n }\n\n // Convert byte array to hex string\n return '0x' + Buffer.from(ownerKeyHash).toString('hex');\n } catch (error) {\n console.error('Error getting vault owner:', error);\n return null;\n }\n }\n\n /**\n * Get authorized signers for a vault\n * \n * @param vaultObjectId - Vault object ID\n * @returns Array of authorized signer key hashes\n */\n async getAuthorizedSigners(vaultObjectId: string): Promise<string[]> {\n try {\n const vaultObject = await this.client.getObject({\n id: vaultObjectId,\n options: { showContent: true },\n });\n\n if (!vaultObject.data?.content || vaultObject.data.content.dataType !== 'moveObject') {\n return [];\n }\n\n const fields = vaultObject.data.content.fields as Record<string, unknown>;\n const authorizedSigners = fields['authorized_signers'] as number[][] | undefined;\n\n if (!authorizedSigners) {\n return [];\n }\n\n // Convert each byte array to hex string\n return authorizedSigners.map(signer => \n '0x' + Buffer.from(signer).toString('hex')\n );\n } catch (error) {\n console.error('Error getting authorized signers:', error);\n return [];\n }\n }\n\n /**\n * Check if a VAA has been processed (for replay protection)\n * \n * @param vaaHash - VAA hash as hex string\n * @param processedVaasObjectId - ProcessedVAAs shared object ID\n * @returns Whether the VAA has been processed\n */\n async isVaaProcessed(\n _vaaHash: string,\n processedVaasObjectId: string\n ): Promise<boolean> {\n try {\n const processedObject = await this.client.getObject({\n id: processedVaasObjectId,\n options: { showContent: true },\n });\n\n if (!processedObject.data?.content) {\n return false;\n }\n\n // Would need to query dynamic field for vaaHash key\n console.warn('isVaaProcessed requires dynamic field query');\n return false;\n } catch (error) {\n console.error('Error checking VAA status:', error);\n return false;\n }\n }\n\n /**\n * Check if protocol is paused\n * \n * @param configObjectId - Config shared object ID\n * @returns Whether the protocol is paused\n */\n async isProtocolPaused(configObjectId: string): Promise<boolean> {\n try {\n const configObject = await this.client.getObject({\n id: configObjectId,\n options: { showContent: true },\n });\n\n if (!configObject.data?.content || configObject.data.content.dataType !== 'moveObject') {\n return false;\n }\n\n const fields = configObject.data.content.fields as Record<string, unknown>;\n return fields['paused'] === true;\n } catch (error) {\n console.error('Error checking pause status:', error);\n return false;\n }\n }\n}\n"],"mappings":"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","names":[]}
|