@veridex/sdk 1.0.0-beta.5 → 1.0.0-beta.7
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/dist/chains/aptos/index.js +3 -3
- package/dist/chains/aptos/index.js.map +1 -1
- package/dist/chains/aptos/index.mjs +3 -3
- package/dist/chains/aptos/index.mjs.map +1 -1
- package/dist/chains/evm/index.js.map +1 -1
- package/dist/chains/evm/index.mjs.map +1 -1
- package/dist/chains/solana/index.js.map +1 -1
- package/dist/chains/solana/index.mjs.map +1 -1
- package/dist/chains/starknet/index.js.map +1 -1
- package/dist/chains/starknet/index.mjs.map +1 -1
- package/dist/chains/sui/index.js.map +1 -1
- package/dist/chains/sui/index.mjs.map +1 -1
- package/dist/constants.js +4 -4
- package/dist/constants.js.map +1 -1
- package/dist/constants.mjs +4 -4
- package/dist/constants.mjs.map +1 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +11 -11
- package/dist/index.mjs.map +1 -1
- package/dist/payload.js.map +1 -1
- package/dist/payload.mjs.map +1 -1
- package/dist/queries/index.js +4 -4
- package/dist/queries/index.js.map +1 -1
- package/dist/queries/index.mjs +4 -4
- package/dist/queries/index.mjs.map +1 -1
- package/dist/utils.js +4 -4
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +4 -4
- package/dist/utils.mjs.map +1 -1
- package/dist/wormhole.js.map +1 -1
- package/dist/wormhole.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -233,12 +233,12 @@ var AptosClient = class {
|
|
|
233
233
|
*/
|
|
234
234
|
async getVaultAddress(userKeyHash) {
|
|
235
235
|
try {
|
|
236
|
-
const
|
|
236
|
+
const keyHashBytes = this.hexToBytes(userKeyHash.replace("0x", "").padStart(64, "0"));
|
|
237
237
|
const payload = {
|
|
238
238
|
function: `${this.moduleAddress}::spoke::get_vault_address`,
|
|
239
239
|
type_arguments: [],
|
|
240
|
-
arguments: [
|
|
241
|
-
// Pass as
|
|
240
|
+
arguments: [Array.from(keyHashBytes)]
|
|
241
|
+
// Pass as array of numbers for vector<u8>
|
|
242
242
|
};
|
|
243
243
|
const response = await this.client.view(payload);
|
|
244
244
|
if (response && response.length > 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/chains/aptos/index.ts","../../../src/chains/aptos/AptosClient.ts","../../../src/payload.ts","../../../src/constants.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Aptos Chain Module \n */\n\nexport { AptosClient } from './AptosClient.js';\nexport type { AptosClientConfig } from './AptosClient.js';\n","/**\n * Veridex Protocol SDK - Aptos Chain Client\n * \n * Implementation of ChainClient interface for Aptos blockchain\n */\n\nimport { AptosClient as AptosSDK, Types } from 'aptos';\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// 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: AptosSDK;\n private moduleAddress: string;\n\n constructor(config: AptosClientConfig) {\n this.config = {\n name: `Aptos ${config.network || 'mainnet'}`,\n chainId: config.wormholeChainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl: config.rpcUrl,\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 this.client = new AptosSDK(config.rpcUrl);\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\n const resource = await this.client.getAccountResource(\n vaultAddress,\n `${this.moduleAddress}::vault::Vault`\n );\n\n if (resource && resource.data) {\n const data = resource.data as any;\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 // Query the on-chain VaultRegistry via view function\n // Module is veridex::spoke (not veridex_spoke)\n // Normalize keyHash to 0x-prefixed 64-char hex string\n const normalizedKeyHash = '0x' + userKeyHash.replace('0x', '').padStart(64, '0');\n \n const payload = {\n function: `${this.moduleAddress}::spoke::get_vault_address`,\n type_arguments: [],\n arguments: [normalizedKeyHash], // Pass as hex string, not byte array\n };\n\n const response = await this.client.view(payload);\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 address,\n '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 ownerAddress,\n `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(): AptosSDK {\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<Types.Transaction> {\n return await this.client.getTransactionByHash(txHash);\n }\n\n /**\n * Wait for transaction confirmation\n */\n async waitForTransaction(txHash: string, timeoutSecs: number = 30): Promise<Types.Transaction> {\n return await this.client.waitForTransactionWithResult(txHash, {\n timeoutSecs,\n checkSuccess: true,\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 vaultAddress,\n `${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 this.moduleAddress,\n `${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 this.moduleAddress,\n `${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","/**\n * Veridex Protocol SDK - Payload Encoding/Decoding Utilities\n */\n\nimport { ethers } from 'ethers';\nimport {\n ACTION_TRANSFER,\n ACTION_EXECUTE,\n ACTION_CONFIG,\n ACTION_BRIDGE,\n PROTOCOL_VERSION,\n} from './constants.js';\nimport type { TransferAction, BridgeAction, ExecuteAction, ActionPayload } from './types.js';\n\n// ============================================================================\n// Action Encoding\n// ============================================================================\n\n/**\n * Encode a transfer action payload\n * Format: [actionType(1)] [token(32)] [recipient(32)] [amount(32)]\n */\nexport function encodeTransferAction(\n token: string,\n recipient: string,\n amount: bigint\n): string {\n const tokenPadded = padTo32Bytes(token);\n const recipientPadded = padTo32Bytes(recipient);\n const amountBytes = ethers.zeroPadValue(ethers.toBeHex(amount), 32);\n\n return ethers.concat([\n ethers.toBeHex(ACTION_TRANSFER, 1),\n tokenPadded,\n recipientPadded,\n amountBytes,\n ]);\n}\n\n/**\n * Encode a bridge action payload\n * Format: [actionType(1)] [token(32)] [amount(32)] [targetChain(2)] [recipient(32)]\n */\nexport function encodeBridgeAction(\n token: string,\n amount: bigint,\n targetChain: number,\n recipient: string\n): string {\n const tokenPadded = padTo32Bytes(token);\n const amountBytes = ethers.zeroPadValue(ethers.toBeHex(amount), 32);\n const targetChainBytes = ethers.toBeHex(targetChain, 2);\n const recipientPadded = padTo32Bytes(recipient);\n\n return ethers.concat([\n ethers.toBeHex(ACTION_BRIDGE, 1),\n tokenPadded,\n amountBytes,\n targetChainBytes,\n recipientPadded,\n ]);\n}\n\n/**\n * Encode an execute action payload (arbitrary contract call)\n * Format: [actionType(1)] [target(32)] [value(32)] [dataLength(2)] [data(variable)]\n */\nexport function encodeExecuteAction(\n target: string,\n value: bigint,\n data: string\n): string {\n const targetPadded = padTo32Bytes(target);\n const valueBytes = ethers.zeroPadValue(ethers.toBeHex(value), 32);\n const dataBytes = ethers.getBytes(data);\n const dataLengthBytes = ethers.toBeHex(dataBytes.length, 2);\n\n return ethers.concat([\n ethers.toBeHex(ACTION_EXECUTE, 1),\n targetPadded,\n valueBytes,\n dataLengthBytes,\n data,\n ]);\n}\n\n/**\n * Encode a config action payload\n * Format: [actionType(1)] [configType(1)] [configData(variable)]\n */\nexport function encodeConfigAction(configType: number, configData: string): string {\n return ethers.concat([\n ethers.toBeHex(ACTION_CONFIG, 1),\n ethers.toBeHex(configType, 1),\n configData,\n ]);\n}\n\n// ============================================================================\n// Veridex Payload Encoding\n// ============================================================================\n\n/**\n * Encode the full Veridex message payload that gets published via Wormhole\n * Format: [version(1)] [userKeyHash(32)] [targetChain(2)] [nonce(32)] [pubKeyX(32)] [pubKeyY(32)] [actionPayload]\n */\nexport function encodeVeridexPayload(\n userKeyHash: string,\n targetChain: number,\n nonce: bigint,\n publicKeyX: bigint,\n publicKeyY: bigint,\n actionPayload: string\n): string {\n return ethers.concat([\n ethers.toBeHex(PROTOCOL_VERSION, 1),\n userKeyHash,\n ethers.toBeHex(targetChain, 2),\n ethers.zeroPadValue(ethers.toBeHex(nonce), 32),\n ethers.zeroPadValue(ethers.toBeHex(publicKeyX), 32),\n ethers.zeroPadValue(ethers.toBeHex(publicKeyY), 32),\n actionPayload,\n ]);\n}\n\n// ============================================================================\n// Action Decoding\n// ============================================================================\n\n/**\n * Decode an action payload to determine its type and contents\n */\nexport function decodeActionPayload(payload: string): ActionPayload {\n const data = ethers.getBytes(payload);\n const actionType = data[0];\n\n switch (actionType) {\n case ACTION_TRANSFER:\n return decodeTransferAction(payload);\n case ACTION_BRIDGE:\n return decodeBridgeAction(payload);\n case ACTION_EXECUTE:\n return decodeExecuteAction(payload);\n default:\n return { type: `unknown_${actionType}`, raw: payload };\n }\n}\n\n/**\n * Decode a transfer action payload\n */\nexport function decodeTransferAction(payload: string): TransferAction {\n const data = ethers.getBytes(payload);\n\n const tokenBytes = data.slice(1, 33);\n const recipientBytes = data.slice(33, 65);\n const amountBytes = data.slice(65, 97);\n\n return {\n type: 'transfer',\n token: trimTo20Bytes(ethers.hexlify(tokenBytes)),\n recipient: trimTo20Bytes(ethers.hexlify(recipientBytes)),\n amount: BigInt(ethers.hexlify(amountBytes)),\n };\n}\n\n/**\n * Decode a bridge action payload\n */\nexport function decodeBridgeAction(payload: string): BridgeAction {\n const data = ethers.getBytes(payload);\n\n const tokenBytes = data.slice(1, 33);\n const amountBytes = data.slice(33, 65);\n const targetChainByte0 = data[65];\n const targetChainByte1 = data[66];\n const recipientBytes = data.slice(67, 99);\n\n const targetChain = ((targetChainByte0 ?? 0) << 8) | (targetChainByte1 ?? 0);\n\n return {\n type: 'bridge',\n token: trimTo20Bytes(ethers.hexlify(tokenBytes)),\n amount: BigInt(ethers.hexlify(amountBytes)),\n targetChain,\n recipient: ethers.hexlify(recipientBytes),\n };\n}\n\n/**\n * Decode an execute action payload\n */\nexport function decodeExecuteAction(payload: string): ExecuteAction {\n const data = ethers.getBytes(payload);\n\n const targetBytes = data.slice(1, 33);\n const valueBytes = data.slice(33, 65);\n const dataLengthByte0 = data[65];\n const dataLengthByte1 = data[66];\n const dataLength = ((dataLengthByte0 ?? 0) << 8) | (dataLengthByte1 ?? 0);\n const callData = data.slice(67, 67 + dataLength);\n\n return {\n type: 'execute',\n target: trimTo20Bytes(ethers.hexlify(targetBytes)),\n value: BigInt(ethers.hexlify(valueBytes)),\n data: ethers.hexlify(callData),\n };\n}\n\n// ============================================================================\n// Chain-Specific Encodings\n// ============================================================================\n\n/**\n * Encode a Solana-compatible transfer action\n * Solana uses: [actionType(1)] [amount(8 LE)] [recipient(32)]\n */\nexport function encodeSolanaTransferAction(\n amount: bigint,\n recipient: string\n): string {\n const amountBytes = Buffer.alloc(8);\n amountBytes.writeBigUInt64LE(amount);\n\n const recipientBytes = ethers.getBytes(recipient);\n\n return ethers.hexlify(\n Buffer.concat([\n Buffer.from([ACTION_TRANSFER]),\n amountBytes,\n Buffer.from(recipientBytes),\n ])\n );\n}\n\n/**\n * Encode an Aptos-compatible transfer action\n * Aptos uses: [actionType(1)] [amount(8 LE)] [recipient(32)]\n */\nexport function encodeAptosTransferAction(\n amount: bigint,\n recipient: string\n): string {\n const amountBytes = Buffer.alloc(8);\n amountBytes.writeBigUInt64LE(amount);\n\n const recipientPadded = padTo32Bytes(recipient);\n\n return ethers.hexlify(\n Buffer.concat([\n Buffer.from([ACTION_TRANSFER]),\n amountBytes,\n Buffer.from(ethers.getBytes(recipientPadded)),\n ])\n );\n}\n\n/**\n * Encode a Sui-compatible transfer action\n * Sui uses: [actionType(1)] [amount(8 LE)] [recipient(32)]\n */\nexport function encodeSuiTransferAction(\n amount: bigint,\n recipient: string\n): string {\n const amountBytes = Buffer.alloc(8);\n amountBytes.writeBigUInt64LE(amount);\n\n const recipientPadded = padTo32Bytes(recipient);\n\n return ethers.hexlify(\n Buffer.concat([\n Buffer.from([ACTION_TRANSFER]),\n amountBytes,\n Buffer.from(ethers.getBytes(recipientPadded)),\n ])\n );\n}\n\n// ============================================================================\n// Address Utilities\n// ============================================================================\n\n/**\n * Pad an address to 32 bytes (Wormhole standard)\n * Supports both EVM addresses (0x...) and Solana addresses (base58)\n */\nexport function padTo32Bytes(address: string): string {\n // Handle native token - convert to zero address\n if (address.toLowerCase() === 'native') {\n return '0x' + '0'.repeat(64);\n }\n \n // If it starts with 0x, treat as hex\n if (address.startsWith('0x')) {\n const hex = address.replace('0x', '');\n // Validate that hex only contains valid hex characters\n if (!/^[0-9a-fA-F]*$/.test(hex)) {\n throw new Error(`Invalid address: ${address}. Expected hex string or 'native'.`);\n }\n return '0x' + hex.padStart(64, '0');\n }\n \n // Otherwise, assume base58 Solana address and decode it\n // Base58 character set (Bitcoin/Solana style - no 0, O, I, l)\n const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n \n // Validate base58 characters\n for (const char of address) {\n if (!base58Chars.includes(char)) {\n throw new Error(`Invalid address: ${address}. Contains invalid base58 character '${char}'.`);\n }\n }\n \n // Decode base58 to bytes\n let value = BigInt(0);\n for (const char of address) {\n value = value * 58n + BigInt(base58Chars.indexOf(char));\n }\n \n // Convert to 32-byte hex\n let hex = value.toString(16);\n // Ensure it's not longer than 64 chars (32 bytes)\n if (hex.length > 64) {\n throw new Error(`Invalid address: ${address}. Decoded value too large for 32 bytes.`);\n }\n \n return '0x' + hex.padStart(64, '0');\n}\n\n/**\n * Trim a 32-byte hex to a 20-byte EVM address\n */\nexport function trimTo20Bytes(hex32: string): string {\n const clean = hex32.replace('0x', '');\n return '0x' + clean.slice(-40);\n}\n\n/**\n * Convert a Solana public key (base58) to bytes32\n * @deprecated Use padTo32Bytes instead, which now handles both EVM and Solana addresses\n */\nexport function solanaAddressToBytes32(base58Address: string): string {\n return padTo32Bytes(base58Address);\n}\n\n// ============================================================================\n// Amount Utilities\n// ============================================================================\n\n/**\n * Format an amount with decimals for display\n */\nexport function formatAmount(amount: bigint, decimals = 18): string {\n const divisor = 10n ** BigInt(decimals);\n const whole = amount / divisor;\n const fraction = amount % divisor;\n\n if (fraction === 0n) {\n return whole.toString();\n }\n\n const fractionStr = fraction.toString().padStart(decimals, '0');\n const trimmedFraction = fractionStr.replace(/0+$/, '');\n\n return `${whole}.${trimmedFraction}`;\n}\n\n/**\n * Parse an amount string with decimals to bigint\n */\nexport function parseAmount(amountStr: string, decimals = 18): bigint {\n const parts = amountStr.split('.');\n const whole = BigInt(parts[0] ?? '0');\n\n if (parts.length === 1 || !parts[1]) {\n return whole * (10n ** BigInt(decimals));\n }\n\n const fractionStr = parts[1].slice(0, decimals).padEnd(decimals, '0');\n const fraction = BigInt(fractionStr);\n\n return whole * (10n ** BigInt(decimals)) + fraction;\n}\n\n// ============================================================================\n// Nonce Utilities\n// ============================================================================\n\n/**\n * Generate a unique nonce for a transaction\n */\nexport function generateNonce(): bigint {\n const timestamp = BigInt(Date.now());\n const random = BigInt(Math.floor(Math.random() * 1000000));\n return (timestamp << 20n) | random;\n}\n\n/**\n * Create a message hash for signing (used in authenticateRawAndDispatch)\n */\nexport function createMessageHash(\n targetChain: number,\n actionPayload: string,\n nonce: bigint\n): string {\n return ethers.keccak256(\n ethers.solidityPacked(\n ['uint16', 'bytes', 'uint256'],\n [targetChain, actionPayload, nonce]\n )\n );\n}\n\n/**\n * Create the challenge bytes for gasless dispatch (matches Hub's authenticateAndDispatch)\n * \n * The Hub contract passes raw packed bytes to WebAuthn.verify():\n * abi.encodePacked(targetChain, actionPayload, userNonce, hubChainId)\n * \n * The WebAuthn library then base64url-encodes these bytes to match against clientDataJSON.\n * We do NOT hash here - the challenge is the raw packed bytes.\n * \n * @param targetChain - Wormhole chain ID of the destination\n * @param actionPayload - The action payload (hex string)\n * @param nonce - User's current nonce\n * @param hubChainId - Wormhole chain ID of the Hub (e.g., 30 for Base)\n * @returns The packed bytes as hex string (NOT hashed)\n */\nexport function createGaslessMessageHash(\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n hubChainId: number\n): string {\n // Return raw packed bytes - NO sha256 hash\n // The contract passes these bytes directly to WebAuthn.verify()\n return ethers.solidityPacked(\n ['uint16', 'bytes', 'uint256', 'uint16'],\n [targetChain, actionPayload, nonce, hubChainId]\n );\n}\n\n/**\n * Build the challenge bytes for WebAuthn signing (gasless flow)\n * Returns raw packed bytes that match what the Hub contract expects\n * \n * @param targetChain - Wormhole chain ID of the destination\n * @param actionPayload - The action payload (hex string)\n * @param nonce - User's current nonce\n * @param hubChainId - Wormhole chain ID of the Hub\n * @returns Challenge bytes for WebAuthn signing (raw packed, not hashed)\n */\nexport function buildGaslessChallenge(\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n hubChainId: number\n): Uint8Array {\n const packed = createGaslessMessageHash(targetChain, actionPayload, nonce, hubChainId);\n return ethers.getBytes(packed);\n}\n\n/**\n * Build the challenge bytes for WebAuthn signing\n */\nexport function buildChallenge(\n userKeyHash: string,\n targetChain: number,\n nonce: bigint,\n actionPayload: string\n): Uint8Array {\n const encoded = ethers.solidityPacked(\n ['bytes32', 'uint16', 'uint256', 'bytes'],\n [userKeyHash, targetChain, nonce, actionPayload]\n );\n return ethers.getBytes(ethers.keccak256(encoded));\n}\n","/**\n * Veridex Protocol SDK - Constants and Chain Configurations\n */\n\nimport type { ChainConfig } from './types.js';\n\n// ============================================================================\n// Action Type Constants\n// ============================================================================\n\nexport const ACTION_TYPES = {\n TRANSFER: 1,\n EXECUTE: 2,\n CONFIG: 3,\n BRIDGE: 4,\n} as const;\n\nexport const ACTION_TRANSFER = 1;\nexport const ACTION_EXECUTE = 2;\nexport const ACTION_CONFIG = 3;\nexport const ACTION_BRIDGE = 4;\n\n// Protocol version\nexport const PROTOCOL_VERSION = 1;\n\n// ============================================================================\n// Wormhole Chain IDs\n// ============================================================================\n\n/**\n * Wormhole Chain IDs organized by network\n * @see https://docs.wormhole.com/wormhole/reference/constants\n */\nexport const WORMHOLE_CHAIN_IDS = {\n MAINNET: {\n SOLANA: 1,\n ETHEREUM: 2,\n TERRA: 3,\n BSC: 4,\n POLYGON: 5,\n AVALANCHE: 6,\n OASIS: 7,\n ALGORAND: 8,\n AURORA: 9,\n FANTOM: 10,\n KARURA: 11,\n ACALA: 12,\n KLAYTN: 13,\n CELO: 14,\n NEAR: 15,\n MOONBEAM: 16,\n NEON: 17,\n TERRA2: 18,\n INJECTIVE: 19,\n OSMOSIS: 20,\n SUI: 21,\n APTOS: 22,\n ARBITRUM: 23,\n OPTIMISM: 24,\n GNOSIS: 25,\n PYTHNET: 26,\n XPLA: 28,\n BASE: 30,\n SEI: 32,\n ROOTSTOCK: 33,\n SCROLL: 34,\n MANTLE: 35,\n BLAST: 36,\n XLAYER: 37,\n LINEA: 38,\n BERACHAIN: 39,\n SEIEVM: 40,\n },\n TESTNET: {\n SOLANA_DEVNET: 1,\n GOERLI: 2,\n BSC_TESTNET: 4,\n POLYGON_MUMBAI: 5,\n AVALANCHE_FUJI: 6,\n FANTOM_TESTNET: 10,\n CELO_ALFAJORES: 14,\n MOONBASE_ALPHA: 16,\n SUI_TESTNET: 21,\n APTOS_TESTNET: 22,\n SEPOLIA: 10002,\n ARBITRUM_SEPOLIA: 10003,\n BASE_SEPOLIA: 10004,\n OPTIMISM_SEPOLIA: 10005,\n HOLESKY: 10006,\n POLYGON_SEPOLIA: 10007,\n SEI_ATLANTIC_2: 10066, // Sei Arctic-1 testnet (EVM)\n STARKNET_SEPOLIA: 50001, // Custom bridge (non-Wormhole, relayer-attested)\n },\n} as const;\n\n// Legacy flat exports for backward compatibility\nexport const WORMHOLE_CHAIN_IDS_FLAT = {\n // Mainnets\n SOLANA: 1,\n ETHEREUM: 2,\n TERRA: 3,\n BSC: 4,\n POLYGON: 5,\n AVALANCHE: 6,\n OASIS: 7,\n ALGORAND: 8,\n AURORA: 9,\n FANTOM: 10,\n KARURA: 11,\n ACALA: 12,\n KLAYTN: 13,\n CELO: 14,\n NEAR: 15,\n MOONBEAM: 16,\n NEON: 17,\n TERRA2: 18,\n INJECTIVE: 19,\n OSMOSIS: 20,\n SUI: 21,\n APTOS: 22,\n ARBITRUM: 23,\n OPTIMISM: 24,\n GNOSIS: 25,\n PYTHNET: 26,\n XPLA: 28,\n BASE: 30,\n SEI: 32,\n ROOTSTOCK: 33,\n SCROLL: 34,\n MANTLE: 35,\n BLAST: 36,\n XLAYER: 37,\n LINEA: 38,\n BERACHAIN: 39,\n SEIEVM: 40,\n\n // Testnets\n SOLANA_DEVNET: 1,\n GOERLI: 2,\n BSC_TESTNET: 4,\n POLYGON_MUMBAI: 5,\n AVALANCHE_FUJI: 6,\n FANTOM_TESTNET: 10,\n CELO_ALFAJORES: 14,\n MOONBASE_ALPHA: 16,\n SUI_TESTNET: 21,\n APTOS_TESTNET: 22,\n ARBITRUM_SEPOLIA: 10003,\n BASE_SEPOLIA: 10004,\n OPTIMISM_SEPOLIA: 10005,\n POLYGON_SEPOLIA: 10007,\n HOLESKY: 10006,\n STARKNET_SEPOLIA: 50001, // Custom bridge (non-Wormhole)\n} as const;\n\n// ============================================================================\n// Testnet Chain Configurations\n// ============================================================================\n\nexport const TESTNET_CHAINS: Record<string, ChainConfig> = {\n baseSepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n wormholeChainId: 10004,\n rpcUrl: 'https://sepolia.base.org', // Public CORS-friendly RPC\n explorerUrl: 'https://sepolia.basescan.org',\n isEvm: true,\n contracts: {\n hub: '0x66D87dE68327f48A099c5B9bE97020Feab9a7c82',\n vaultFactory: '0x40D9B16094808Fa48e73598E31AB964Cf15b475f',\n vaultImplementation: '0xcBEb49b0109E61c1C69C51D5D9483A3aD6D18258',\n wormholeCoreBridge: '0x79A1027a6A159502049F10906D333EC57E95F083',\n tokenBridge: '0x86F55A04690fd7815A3D802bD587e83eA888B239',\n },\n },\n optimismSepolia: {\n name: 'Optimism Sepolia',\n chainId: 11155420,\n wormholeChainId: 10005,\n rpcUrl: 'https://sepolia.optimism.io',\n explorerUrl: 'https://sepolia-optimism.etherscan.io',\n isEvm: true,\n contracts: {\n vaultFactory: '0xAbB421166E648953CDBE93c0078a0A794c56Fb84',\n vaultImplementation: '0xDCD7daEf1AC06f4a8392957cca4834F7a16c058D',\n wormholeCoreBridge: '0x31377888146f3253211EFEf5c676D41ECe7D58Fe',\n tokenBridge: '0x99737Ec4B815d816c49A385943baf0380e75c0Ac',\n },\n },\n arbitrumSepolia: {\n name: 'Arbitrum Sepolia',\n chainId: 421614,\n wormholeChainId: 10003,\n rpcUrl: 'https://sepolia-rollup.arbitrum.io/rpc',\n explorerUrl: 'https://sepolia.arbiscan.io',\n isEvm: true,\n contracts: {\n vaultFactory: '0xd36D3D5DB59d78f1E33813490F72DABC15C9B07c',\n vaultImplementation: '0xB10ACf39eBF17fc33F722cBD955b7aeCB0611bc4',\n wormholeCoreBridge: '0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35',\n tokenBridge: '0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e',\n },\n },\n seiTestnet: {\n name: 'Sei Atlantic-2',\n chainId: 1328,\n wormholeChainId: 40,\n rpcUrl: 'https://evm-rpc-testnet.sei-apis.com',\n explorerUrl: 'https://seitrace.com/?chain=atlantic-2',\n isEvm: true,\n contracts: {\n vaultFactory: '0x07F608AFf6d63b68029488b726d895c4Bb593038',\n vaultImplementation: '0xD66153fccFB6731fB6c4944FbD607ba86A76a1f6',\n wormholeCoreBridge: '0x0000000000000000000000000000000000000000', // Mock - not yet deployed\n },\n },\n solanaDevnet: {\n name: 'Solana Devnet',\n chainId: 0,\n wormholeChainId: 1,\n rpcUrl: 'https://api.devnet.solana.com',\n explorerUrl: 'https://explorer.solana.com',\n isEvm: false,\n contracts: {\n hub: 'AnyXHsqq9c2BiW4WgBcj6Aye7Ua7a7L7iSuwpfJxECJM',\n wormholeCoreBridge: '3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5',\n tokenBridge: 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe',\n },\n },\n aptosTestnet: {\n name: 'Aptos Testnet',\n chainId: 0,\n wormholeChainId: 22,\n rpcUrl: 'https://fullnode.testnet.aptoslabs.com/v1',\n explorerUrl: 'https://explorer.aptoslabs.com',\n isEvm: false,\n contracts: {\n hub: '0x1a89da9e9f8f0bc90d8d492890bd55fb261c6277d2a95dfcac70c268d0c23dcc',\n wormholeCoreBridge: '0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625',\n tokenBridge: '0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f',\n },\n },\n suiTestnet: {\n name: 'Sui Testnet',\n chainId: 0,\n wormholeChainId: 21,\n rpcUrl: 'https://fullnode.testnet.sui.io:443',\n explorerUrl: 'https://suiscan.xyz/testnet',\n isEvm: false,\n contracts: {\n hub: '0x35e99fdbbc1cde7e093da6f9e758ba2c4a077904bd64caee2fa6db5e6c4e9e37',\n wormholeCoreBridge: '0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790',\n },\n },\n starknetSepolia: {\n name: 'Starknet Sepolia',\n chainId: 0, // Native Starknet chain ID (SN_SEPOLIA = 0x534e5f5345504f4c4941)\n wormholeChainId: 50001, // Custom chain ID (50000+ reserved for non-Wormhole chains)\n rpcUrl: 'https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/tsOnfTBZDKMXcUA26OED-',\n explorerUrl: 'https://sepolia.starkscan.co',\n isEvm: false,\n contracts: {\n // Starknet spoke contract\n hub: '0x68adcc730ed6c355200d00f763825448497b9cdf7936ca121711e078c88e811',\n // Custom bridge contract (NOT Wormhole)\n wormholeCoreBridge: '0x2c458c1ae64556482b05cc2d3ee5b032ed114d68429dda2062c9849a5a725f8',\n },\n // Hub chain ID that Starknet bridge validates (Base Sepolia = 10004)\n hubChainId: 10004,\n },\n};\n\n// ============================================================================\n// Mainnet Chain Configurations\n// ============================================================================\n\nexport const MAINNET_CHAINS: Record<string, ChainConfig> = {\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n wormholeChainId: 2,\n rpcUrl: 'https://eth.llamarpc.com',\n explorerUrl: 'https://etherscan.io',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B',\n tokenBridge: '0x3ee18B2214AFF97000D974cf647E7C347E8fa585',\n },\n },\n base: {\n name: 'Base',\n chainId: 8453,\n wormholeChainId: 30,\n rpcUrl: 'https://mainnet.base.org',\n explorerUrl: 'https://basescan.org',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6',\n tokenBridge: '0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627',\n },\n },\n optimism: {\n name: 'Optimism',\n chainId: 10,\n wormholeChainId: 24,\n rpcUrl: 'https://mainnet.optimism.io',\n explorerUrl: 'https://optimistic.etherscan.io',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722',\n tokenBridge: '0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b',\n },\n },\n arbitrum: {\n name: 'Arbitrum',\n chainId: 42161,\n wormholeChainId: 23,\n rpcUrl: 'https://arb1.arbitrum.io/rpc',\n explorerUrl: 'https://arbiscan.io',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0xa5f208e072434bC67592E4C49C1B991BA79BCA46',\n tokenBridge: '0x0b2402144Bb366A632D14B83F244D2e0e21bD39c',\n },\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n wormholeChainId: 5,\n rpcUrl: 'https://polygon-rpc.com',\n explorerUrl: 'https://polygonscan.com',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7',\n tokenBridge: '0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE',\n },\n },\n solana: {\n name: 'Solana',\n chainId: 0,\n wormholeChainId: 1,\n rpcUrl: 'https://api.mainnet-beta.solana.com',\n explorerUrl: 'https://explorer.solana.com',\n isEvm: false,\n contracts: {\n wormholeCoreBridge: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth',\n tokenBridge: 'wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb',\n },\n },\n aptos: {\n name: 'Aptos',\n chainId: 0,\n wormholeChainId: 22,\n rpcUrl: 'https://fullnode.mainnet.aptoslabs.com/v1',\n explorerUrl: 'https://explorer.aptoslabs.com',\n isEvm: false,\n contracts: {\n wormholeCoreBridge: '0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625',\n tokenBridge: '0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f',\n },\n },\n sui: {\n name: 'Sui',\n chainId: 0,\n wormholeChainId: 21,\n rpcUrl: 'https://fullnode.mainnet.sui.io:443',\n explorerUrl: 'https://suiscan.xyz/mainnet',\n isEvm: false,\n contracts: {\n wormholeCoreBridge: '0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c',\n },\n },\n};\n\n// ============================================================================\n// Wormhole API Endpoints\n// ============================================================================\n\nexport const WORMHOLE_API = {\n MAINNET: 'https://api.wormholescan.io',\n TESTNET: 'https://api.testnet.wormholescan.io',\n GUARDIAN_RPC_MAINNET: 'https://wormhole-v2-mainnet-api.certus.one',\n GUARDIAN_RPC_TESTNET: 'https://wormhole-v2-testnet-api.certus.one',\n} as const;\n\n// ============================================================================\n// Hub Contract ABI (minimal)\n// ============================================================================\n\nexport const HUB_ABI = [\n 'function authenticateAndDispatch((bytes authenticatorData, string clientDataJSON, uint256 challengeIndex, uint256 typeIndex, uint256 r, uint256 s) auth, uint256 publicKeyX, uint256 publicKeyY, uint16 targetChain, bytes actionPayload) external payable returns (uint64 sequence)',\n 'function authenticateRawAndDispatch(uint256 r, uint256 s, bytes32 messageHash, uint256 publicKeyX, uint256 publicKeyY, uint16 targetChain, bytes actionPayload, uint256 nonce) external payable returns (uint64 sequence)',\n 'function getNonce(bytes32 userKeyHash) external view returns (uint256)',\n 'function encodeTransferAction(address token, address recipient, uint256 amount) external pure returns (bytes)',\n 'function encodeExecuteAction(address target, uint256 value, bytes data) external pure returns (bytes)',\n 'function encodeBridgeAction(bytes32 token, uint256 amount, uint16 targetChain, bytes32 recipient) external pure returns (bytes)',\n 'function messageFee() external view returns (uint256)',\n 'event Dispatched(bytes32 indexed userKeyHash, uint16 targetChain, uint256 nonce, uint64 sequence, bytes actionPayload)',\n] as const;\n\n// ============================================================================\n// Vault Factory ABI (minimal)\n// ============================================================================\n\nexport const VAULT_FACTORY_ABI = [\n 'function createVault(bytes32 userKeyHash) external returns (address)',\n 'function getVault(bytes32 userKeyHash) external view returns (address)',\n 'function vaultExists(bytes32 userKeyHash) external view returns (bool)',\n 'event VaultCreated(bytes32 indexed userKeyHash, address vault)',\n] as const;\n\n// ============================================================================\n// Vault ABI (minimal)\n// ============================================================================\n\nexport const VAULT_ABI = [\n 'function execute(address target, uint256 value, bytes data) external returns (bytes)',\n 'function executeFromHub(bytes32 vaaHash, uint16 emitterChain, bytes32 emitterAddress, bytes payload) external',\n 'function owner() external view returns (bytes32)',\n 'function hub() external view returns (address)',\n 'receive() external payable',\n] as const;\n"],"mappings":"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","names":["hex","AptosSDK"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/chains/aptos/index.ts","../../../src/chains/aptos/AptosClient.ts","../../../src/payload.ts","../../../src/constants.ts"],"sourcesContent":["/**\n * Veridex Protocol SDK - Aptos Chain Module \n */\n\nexport { AptosClient } from './AptosClient.js';\nexport type { AptosClientConfig } from './AptosClient.js';\n","/**\n * Veridex Protocol SDK - Aptos Chain Client\n * \n * Implementation of ChainClient interface for Aptos blockchain\n */\n\nimport { AptosClient as AptosSDK, Types } from 'aptos';\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// 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: AptosSDK;\n private moduleAddress: string;\n\n constructor(config: AptosClientConfig) {\n this.config = {\n name: `Aptos ${config.network || 'mainnet'}`,\n chainId: config.wormholeChainId,\n wormholeChainId: config.wormholeChainId,\n rpcUrl: config.rpcUrl,\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 this.client = new AptosSDK(config.rpcUrl);\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\n const resource = await this.client.getAccountResource(\n vaultAddress,\n `${this.moduleAddress}::vault::Vault`\n );\n\n if (resource && resource.data) {\n const data = resource.data as any;\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 // Query the on-chain VaultRegistry via view function\n // The Move function expects vector<u8>, so we convert hex to byte array\n const keyHashBytes = this.hexToBytes(userKeyHash.replace('0x', '').padStart(64, '0'));\n \n const payload = {\n function: `${this.moduleAddress}::spoke::get_vault_address`,\n type_arguments: [],\n arguments: [Array.from(keyHashBytes)], // Pass as array of numbers for vector<u8>\n };\n\n const response = await this.client.view(payload);\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 address,\n '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 ownerAddress,\n `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(): AptosSDK {\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<Types.Transaction> {\n return await this.client.getTransactionByHash(txHash);\n }\n\n /**\n * Wait for transaction confirmation\n */\n async waitForTransaction(txHash: string, timeoutSecs: number = 30): Promise<Types.Transaction> {\n return await this.client.waitForTransactionWithResult(txHash, {\n timeoutSecs,\n checkSuccess: true,\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 vaultAddress,\n `${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 this.moduleAddress,\n `${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 this.moduleAddress,\n `${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","/**\n * Veridex Protocol SDK - Payload Encoding/Decoding Utilities\n */\n\nimport { ethers } from 'ethers';\nimport {\n ACTION_TRANSFER,\n ACTION_EXECUTE,\n ACTION_CONFIG,\n ACTION_BRIDGE,\n PROTOCOL_VERSION,\n} from './constants.js';\nimport type { TransferAction, BridgeAction, ExecuteAction, ActionPayload } from './types.js';\n\n// ============================================================================\n// Action Encoding\n// ============================================================================\n\n/**\n * Encode a transfer action payload\n * Format: [actionType(1)] [token(32)] [recipient(32)] [amount(32)]\n */\nexport function encodeTransferAction(\n token: string,\n recipient: string,\n amount: bigint\n): string {\n const tokenPadded = padTo32Bytes(token);\n const recipientPadded = padTo32Bytes(recipient);\n const amountBytes = ethers.zeroPadValue(ethers.toBeHex(amount), 32);\n\n return ethers.concat([\n ethers.toBeHex(ACTION_TRANSFER, 1),\n tokenPadded,\n recipientPadded,\n amountBytes,\n ]);\n}\n\n/**\n * Encode a bridge action payload\n * Format: [actionType(1)] [token(32)] [amount(32)] [targetChain(2)] [recipient(32)]\n */\nexport function encodeBridgeAction(\n token: string,\n amount: bigint,\n targetChain: number,\n recipient: string\n): string {\n const tokenPadded = padTo32Bytes(token);\n const amountBytes = ethers.zeroPadValue(ethers.toBeHex(amount), 32);\n const targetChainBytes = ethers.toBeHex(targetChain, 2);\n const recipientPadded = padTo32Bytes(recipient);\n\n return ethers.concat([\n ethers.toBeHex(ACTION_BRIDGE, 1),\n tokenPadded,\n amountBytes,\n targetChainBytes,\n recipientPadded,\n ]);\n}\n\n/**\n * Encode an execute action payload (arbitrary contract call)\n * Format: [actionType(1)] [target(32)] [value(32)] [dataLength(2)] [data(variable)]\n */\nexport function encodeExecuteAction(\n target: string,\n value: bigint,\n data: string\n): string {\n const targetPadded = padTo32Bytes(target);\n const valueBytes = ethers.zeroPadValue(ethers.toBeHex(value), 32);\n const dataBytes = ethers.getBytes(data);\n const dataLengthBytes = ethers.toBeHex(dataBytes.length, 2);\n\n return ethers.concat([\n ethers.toBeHex(ACTION_EXECUTE, 1),\n targetPadded,\n valueBytes,\n dataLengthBytes,\n data,\n ]);\n}\n\n/**\n * Encode a config action payload\n * Format: [actionType(1)] [configType(1)] [configData(variable)]\n */\nexport function encodeConfigAction(configType: number, configData: string): string {\n return ethers.concat([\n ethers.toBeHex(ACTION_CONFIG, 1),\n ethers.toBeHex(configType, 1),\n configData,\n ]);\n}\n\n// ============================================================================\n// Veridex Payload Encoding\n// ============================================================================\n\n/**\n * Encode the full Veridex message payload that gets published via Wormhole\n * Format: [version(1)] [userKeyHash(32)] [targetChain(2)] [nonce(32)] [pubKeyX(32)] [pubKeyY(32)] [actionPayload]\n */\nexport function encodeVeridexPayload(\n userKeyHash: string,\n targetChain: number,\n nonce: bigint,\n publicKeyX: bigint,\n publicKeyY: bigint,\n actionPayload: string\n): string {\n return ethers.concat([\n ethers.toBeHex(PROTOCOL_VERSION, 1),\n userKeyHash,\n ethers.toBeHex(targetChain, 2),\n ethers.zeroPadValue(ethers.toBeHex(nonce), 32),\n ethers.zeroPadValue(ethers.toBeHex(publicKeyX), 32),\n ethers.zeroPadValue(ethers.toBeHex(publicKeyY), 32),\n actionPayload,\n ]);\n}\n\n// ============================================================================\n// Action Decoding\n// ============================================================================\n\n/**\n * Decode an action payload to determine its type and contents\n */\nexport function decodeActionPayload(payload: string): ActionPayload {\n const data = ethers.getBytes(payload);\n const actionType = data[0];\n\n switch (actionType) {\n case ACTION_TRANSFER:\n return decodeTransferAction(payload);\n case ACTION_BRIDGE:\n return decodeBridgeAction(payload);\n case ACTION_EXECUTE:\n return decodeExecuteAction(payload);\n default:\n return { type: `unknown_${actionType}`, raw: payload };\n }\n}\n\n/**\n * Decode a transfer action payload\n */\nexport function decodeTransferAction(payload: string): TransferAction {\n const data = ethers.getBytes(payload);\n\n const tokenBytes = data.slice(1, 33);\n const recipientBytes = data.slice(33, 65);\n const amountBytes = data.slice(65, 97);\n\n return {\n type: 'transfer',\n token: trimTo20Bytes(ethers.hexlify(tokenBytes)),\n recipient: trimTo20Bytes(ethers.hexlify(recipientBytes)),\n amount: BigInt(ethers.hexlify(amountBytes)),\n };\n}\n\n/**\n * Decode a bridge action payload\n */\nexport function decodeBridgeAction(payload: string): BridgeAction {\n const data = ethers.getBytes(payload);\n\n const tokenBytes = data.slice(1, 33);\n const amountBytes = data.slice(33, 65);\n const targetChainByte0 = data[65];\n const targetChainByte1 = data[66];\n const recipientBytes = data.slice(67, 99);\n\n const targetChain = ((targetChainByte0 ?? 0) << 8) | (targetChainByte1 ?? 0);\n\n return {\n type: 'bridge',\n token: trimTo20Bytes(ethers.hexlify(tokenBytes)),\n amount: BigInt(ethers.hexlify(amountBytes)),\n targetChain,\n recipient: ethers.hexlify(recipientBytes),\n };\n}\n\n/**\n * Decode an execute action payload\n */\nexport function decodeExecuteAction(payload: string): ExecuteAction {\n const data = ethers.getBytes(payload);\n\n const targetBytes = data.slice(1, 33);\n const valueBytes = data.slice(33, 65);\n const dataLengthByte0 = data[65];\n const dataLengthByte1 = data[66];\n const dataLength = ((dataLengthByte0 ?? 0) << 8) | (dataLengthByte1 ?? 0);\n const callData = data.slice(67, 67 + dataLength);\n\n return {\n type: 'execute',\n target: trimTo20Bytes(ethers.hexlify(targetBytes)),\n value: BigInt(ethers.hexlify(valueBytes)),\n data: ethers.hexlify(callData),\n };\n}\n\n// ============================================================================\n// Chain-Specific Encodings\n// ============================================================================\n\n/**\n * Encode a Solana-compatible transfer action\n * Solana uses: [actionType(1)] [amount(8 LE)] [recipient(32)]\n */\nexport function encodeSolanaTransferAction(\n amount: bigint,\n recipient: string\n): string {\n const amountBytes = Buffer.alloc(8);\n amountBytes.writeBigUInt64LE(amount);\n\n const recipientBytes = ethers.getBytes(recipient);\n\n return ethers.hexlify(\n Buffer.concat([\n Buffer.from([ACTION_TRANSFER]),\n amountBytes,\n Buffer.from(recipientBytes),\n ])\n );\n}\n\n/**\n * Encode an Aptos-compatible transfer action\n * Aptos uses: [actionType(1)] [amount(8 LE)] [recipient(32)]\n */\nexport function encodeAptosTransferAction(\n amount: bigint,\n recipient: string\n): string {\n const amountBytes = Buffer.alloc(8);\n amountBytes.writeBigUInt64LE(amount);\n\n const recipientPadded = padTo32Bytes(recipient);\n\n return ethers.hexlify(\n Buffer.concat([\n Buffer.from([ACTION_TRANSFER]),\n amountBytes,\n Buffer.from(ethers.getBytes(recipientPadded)),\n ])\n );\n}\n\n/**\n * Encode a Sui-compatible transfer action\n * Sui uses: [actionType(1)] [amount(8 LE)] [recipient(32)]\n */\nexport function encodeSuiTransferAction(\n amount: bigint,\n recipient: string\n): string {\n const amountBytes = Buffer.alloc(8);\n amountBytes.writeBigUInt64LE(amount);\n\n const recipientPadded = padTo32Bytes(recipient);\n\n return ethers.hexlify(\n Buffer.concat([\n Buffer.from([ACTION_TRANSFER]),\n amountBytes,\n Buffer.from(ethers.getBytes(recipientPadded)),\n ])\n );\n}\n\n// ============================================================================\n// Address Utilities\n// ============================================================================\n\n/**\n * Pad an address to 32 bytes (Wormhole standard)\n * Supports both EVM addresses (0x...) and Solana addresses (base58)\n */\nexport function padTo32Bytes(address: string): string {\n // Handle native token - convert to zero address\n if (address.toLowerCase() === 'native') {\n return '0x' + '0'.repeat(64);\n }\n \n // If it starts with 0x, treat as hex\n if (address.startsWith('0x')) {\n const hex = address.replace('0x', '');\n // Validate that hex only contains valid hex characters\n if (!/^[0-9a-fA-F]*$/.test(hex)) {\n throw new Error(`Invalid address: ${address}. Expected hex string or 'native'.`);\n }\n return '0x' + hex.padStart(64, '0');\n }\n \n // Otherwise, assume base58 Solana address and decode it\n // Base58 character set (Bitcoin/Solana style - no 0, O, I, l)\n const base58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\n \n // Validate base58 characters\n for (const char of address) {\n if (!base58Chars.includes(char)) {\n throw new Error(`Invalid address: ${address}. Contains invalid base58 character '${char}'.`);\n }\n }\n \n // Decode base58 to bytes\n let value = BigInt(0);\n for (const char of address) {\n value = value * 58n + BigInt(base58Chars.indexOf(char));\n }\n \n // Convert to 32-byte hex\n let hex = value.toString(16);\n // Ensure it's not longer than 64 chars (32 bytes)\n if (hex.length > 64) {\n throw new Error(`Invalid address: ${address}. Decoded value too large for 32 bytes.`);\n }\n \n return '0x' + hex.padStart(64, '0');\n}\n\n/**\n * Trim a 32-byte hex to a 20-byte EVM address\n */\nexport function trimTo20Bytes(hex32: string): string {\n const clean = hex32.replace('0x', '');\n return '0x' + clean.slice(-40);\n}\n\n/**\n * Convert a Solana public key (base58) to bytes32\n * @deprecated Use padTo32Bytes instead, which now handles both EVM and Solana addresses\n */\nexport function solanaAddressToBytes32(base58Address: string): string {\n return padTo32Bytes(base58Address);\n}\n\n// ============================================================================\n// Amount Utilities\n// ============================================================================\n\n/**\n * Format an amount with decimals for display\n */\nexport function formatAmount(amount: bigint, decimals = 18): string {\n const divisor = 10n ** BigInt(decimals);\n const whole = amount / divisor;\n const fraction = amount % divisor;\n\n if (fraction === 0n) {\n return whole.toString();\n }\n\n const fractionStr = fraction.toString().padStart(decimals, '0');\n const trimmedFraction = fractionStr.replace(/0+$/, '');\n\n return `${whole}.${trimmedFraction}`;\n}\n\n/**\n * Parse an amount string with decimals to bigint\n */\nexport function parseAmount(amountStr: string, decimals = 18): bigint {\n const parts = amountStr.split('.');\n const whole = BigInt(parts[0] ?? '0');\n\n if (parts.length === 1 || !parts[1]) {\n return whole * (10n ** BigInt(decimals));\n }\n\n const fractionStr = parts[1].slice(0, decimals).padEnd(decimals, '0');\n const fraction = BigInt(fractionStr);\n\n return whole * (10n ** BigInt(decimals)) + fraction;\n}\n\n// ============================================================================\n// Nonce Utilities\n// ============================================================================\n\n/**\n * Generate a unique nonce for a transaction\n */\nexport function generateNonce(): bigint {\n const timestamp = BigInt(Date.now());\n const random = BigInt(Math.floor(Math.random() * 1000000));\n return (timestamp << 20n) | random;\n}\n\n/**\n * Create a message hash for signing (used in authenticateRawAndDispatch)\n */\nexport function createMessageHash(\n targetChain: number,\n actionPayload: string,\n nonce: bigint\n): string {\n return ethers.keccak256(\n ethers.solidityPacked(\n ['uint16', 'bytes', 'uint256'],\n [targetChain, actionPayload, nonce]\n )\n );\n}\n\n/**\n * Create the challenge bytes for gasless dispatch (matches Hub's authenticateAndDispatch)\n * \n * The Hub contract passes raw packed bytes to WebAuthn.verify():\n * abi.encodePacked(targetChain, actionPayload, userNonce, hubChainId)\n * \n * The WebAuthn library then base64url-encodes these bytes to match against clientDataJSON.\n * We do NOT hash here - the challenge is the raw packed bytes.\n * \n * @param targetChain - Wormhole chain ID of the destination\n * @param actionPayload - The action payload (hex string)\n * @param nonce - User's current nonce\n * @param hubChainId - Wormhole chain ID of the Hub (e.g., 30 for Base)\n * @returns The packed bytes as hex string (NOT hashed)\n */\nexport function createGaslessMessageHash(\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n hubChainId: number\n): string {\n // Return raw packed bytes - NO sha256 hash\n // The contract passes these bytes directly to WebAuthn.verify()\n return ethers.solidityPacked(\n ['uint16', 'bytes', 'uint256', 'uint16'],\n [targetChain, actionPayload, nonce, hubChainId]\n );\n}\n\n/**\n * Build the challenge bytes for WebAuthn signing (gasless flow)\n * Returns raw packed bytes that match what the Hub contract expects\n * \n * @param targetChain - Wormhole chain ID of the destination\n * @param actionPayload - The action payload (hex string)\n * @param nonce - User's current nonce\n * @param hubChainId - Wormhole chain ID of the Hub\n * @returns Challenge bytes for WebAuthn signing (raw packed, not hashed)\n */\nexport function buildGaslessChallenge(\n targetChain: number,\n actionPayload: string,\n nonce: bigint,\n hubChainId: number\n): Uint8Array {\n const packed = createGaslessMessageHash(targetChain, actionPayload, nonce, hubChainId);\n return ethers.getBytes(packed);\n}\n\n/**\n * Build the challenge bytes for WebAuthn signing\n */\nexport function buildChallenge(\n userKeyHash: string,\n targetChain: number,\n nonce: bigint,\n actionPayload: string\n): Uint8Array {\n const encoded = ethers.solidityPacked(\n ['bytes32', 'uint16', 'uint256', 'bytes'],\n [userKeyHash, targetChain, nonce, actionPayload]\n );\n return ethers.getBytes(ethers.keccak256(encoded));\n}\n","/**\n * Veridex Protocol SDK - Constants and Chain Configurations\n */\n\nimport type { ChainConfig } from './types.js';\n\n// ============================================================================\n// Action Type Constants\n// ============================================================================\n\nexport const ACTION_TYPES = {\n TRANSFER: 1,\n EXECUTE: 2,\n CONFIG: 3,\n BRIDGE: 4,\n} as const;\n\nexport const ACTION_TRANSFER = 1;\nexport const ACTION_EXECUTE = 2;\nexport const ACTION_CONFIG = 3;\nexport const ACTION_BRIDGE = 4;\n\n// Protocol version\nexport const PROTOCOL_VERSION = 1;\n\n// ============================================================================\n// Wormhole Chain IDs\n// ============================================================================\n\n/**\n * Wormhole Chain IDs organized by network\n * @see https://docs.wormhole.com/wormhole/reference/constants\n */\nexport const WORMHOLE_CHAIN_IDS = {\n MAINNET: {\n SOLANA: 1,\n ETHEREUM: 2,\n TERRA: 3,\n BSC: 4,\n POLYGON: 5,\n AVALANCHE: 6,\n OASIS: 7,\n ALGORAND: 8,\n AURORA: 9,\n FANTOM: 10,\n KARURA: 11,\n ACALA: 12,\n KLAYTN: 13,\n CELO: 14,\n NEAR: 15,\n MOONBEAM: 16,\n NEON: 17,\n TERRA2: 18,\n INJECTIVE: 19,\n OSMOSIS: 20,\n SUI: 21,\n APTOS: 22,\n ARBITRUM: 23,\n OPTIMISM: 24,\n GNOSIS: 25,\n PYTHNET: 26,\n XPLA: 28,\n BASE: 30,\n SEI: 32,\n ROOTSTOCK: 33,\n SCROLL: 34,\n MANTLE: 35,\n BLAST: 36,\n XLAYER: 37,\n LINEA: 38,\n BERACHAIN: 39,\n SEIEVM: 40,\n },\n TESTNET: {\n SOLANA_DEVNET: 1,\n GOERLI: 2,\n BSC_TESTNET: 4,\n POLYGON_MUMBAI: 5,\n AVALANCHE_FUJI: 6,\n FANTOM_TESTNET: 10,\n CELO_ALFAJORES: 14,\n MOONBASE_ALPHA: 16,\n SUI_TESTNET: 21,\n APTOS_TESTNET: 22,\n SEPOLIA: 10002,\n ARBITRUM_SEPOLIA: 10003,\n BASE_SEPOLIA: 10004,\n OPTIMISM_SEPOLIA: 10005,\n HOLESKY: 10006,\n POLYGON_SEPOLIA: 10007,\n SEI_ATLANTIC_2: 10066, // Sei Arctic-1 testnet (EVM)\n STARKNET_SEPOLIA: 50001, // Custom bridge (non-Wormhole, relayer-attested)\n },\n} as const;\n\n// Legacy flat exports for backward compatibility\nexport const WORMHOLE_CHAIN_IDS_FLAT = {\n // Mainnets\n SOLANA: 1,\n ETHEREUM: 2,\n TERRA: 3,\n BSC: 4,\n POLYGON: 5,\n AVALANCHE: 6,\n OASIS: 7,\n ALGORAND: 8,\n AURORA: 9,\n FANTOM: 10,\n KARURA: 11,\n ACALA: 12,\n KLAYTN: 13,\n CELO: 14,\n NEAR: 15,\n MOONBEAM: 16,\n NEON: 17,\n TERRA2: 18,\n INJECTIVE: 19,\n OSMOSIS: 20,\n SUI: 21,\n APTOS: 22,\n ARBITRUM: 23,\n OPTIMISM: 24,\n GNOSIS: 25,\n PYTHNET: 26,\n XPLA: 28,\n BASE: 30,\n SEI: 32,\n ROOTSTOCK: 33,\n SCROLL: 34,\n MANTLE: 35,\n BLAST: 36,\n XLAYER: 37,\n LINEA: 38,\n BERACHAIN: 39,\n SEIEVM: 40,\n\n // Testnets\n SOLANA_DEVNET: 1,\n GOERLI: 2,\n BSC_TESTNET: 4,\n POLYGON_MUMBAI: 5,\n AVALANCHE_FUJI: 6,\n FANTOM_TESTNET: 10,\n CELO_ALFAJORES: 14,\n MOONBASE_ALPHA: 16,\n SUI_TESTNET: 21,\n APTOS_TESTNET: 22,\n ARBITRUM_SEPOLIA: 10003,\n BASE_SEPOLIA: 10004,\n OPTIMISM_SEPOLIA: 10005,\n POLYGON_SEPOLIA: 10007,\n HOLESKY: 10006,\n STARKNET_SEPOLIA: 50001, // Custom bridge (non-Wormhole)\n} as const;\n\n// ============================================================================\n// Testnet Chain Configurations\n// ============================================================================\n\nexport const TESTNET_CHAINS: Record<string, ChainConfig> = {\n baseSepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n wormholeChainId: 10004,\n rpcUrl: 'https://sepolia.base.org', // Public CORS-friendly RPC\n explorerUrl: 'https://sepolia.basescan.org',\n isEvm: true,\n contracts: {\n hub: '0x66D87dE68327f48A099c5B9bE97020Feab9a7c82',\n vaultFactory: '0xCFaEb5652aa2Ee60b2229dC8895B4159749C7e53',\n vaultImplementation: '0x0d13367C16c6f0B24eD275CC67C7D9f42878285c',\n wormholeCoreBridge: '0x79A1027a6A159502049F10906D333EC57E95F083',\n tokenBridge: '0x86F55A04690fd7815A3D802bD587e83eA888B239',\n },\n },\n optimismSepolia: {\n name: 'Optimism Sepolia',\n chainId: 11155420,\n wormholeChainId: 10005,\n rpcUrl: 'https://sepolia.optimism.io',\n explorerUrl: 'https://sepolia-optimism.etherscan.io',\n isEvm: true,\n contracts: {\n vaultFactory: '0xA5653d54079ABeCe780F8d9597B2bc4B09fe464A',\n vaultImplementation: '0x8099b1406485d2255ff89Ce5Ea18520802AFC150',\n wormholeCoreBridge: '0x31377888146f3253211EFEf5c676D41ECe7D58Fe',\n tokenBridge: '0x99737Ec4B815d816c49A385943baf0380e75c0Ac',\n },\n },\n arbitrumSepolia: {\n name: 'Arbitrum Sepolia',\n chainId: 421614,\n wormholeChainId: 10003,\n rpcUrl: 'https://sepolia-rollup.arbitrum.io/rpc',\n explorerUrl: 'https://sepolia.arbiscan.io',\n isEvm: true,\n contracts: {\n vaultFactory: '0xd36D3D5DB59d78f1E33813490F72DABC15C9B07c',\n vaultImplementation: '0xB10ACf39eBF17fc33F722cBD955b7aeCB0611bc4',\n wormholeCoreBridge: '0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35',\n tokenBridge: '0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e',\n },\n },\n seiTestnet: {\n name: 'Sei Atlantic-2',\n chainId: 1328,\n wormholeChainId: 40,\n rpcUrl: 'https://evm-rpc-testnet.sei-apis.com',\n explorerUrl: 'https://seitrace.com/?chain=atlantic-2',\n isEvm: true,\n contracts: {\n vaultFactory: '0x07F608AFf6d63b68029488b726d895c4Bb593038',\n vaultImplementation: '0xD66153fccFB6731fB6c4944FbD607ba86A76a1f6',\n wormholeCoreBridge: '0x0000000000000000000000000000000000000000', // Mock - not yet deployed\n },\n },\n solanaDevnet: {\n name: 'Solana Devnet',\n chainId: 0,\n wormholeChainId: 1,\n rpcUrl: 'https://api.devnet.solana.com',\n explorerUrl: 'https://explorer.solana.com',\n isEvm: false,\n contracts: {\n hub: 'AnyXHsqq9c2BiW4WgBcj6Aye7Ua7a7L7iSuwpfJxECJM',\n wormholeCoreBridge: '3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5',\n tokenBridge: 'DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe',\n },\n },\n aptosTestnet: {\n name: 'Aptos Testnet',\n chainId: 0,\n wormholeChainId: 22,\n rpcUrl: 'https://fullnode.testnet.aptoslabs.com/v1',\n explorerUrl: 'https://explorer.aptoslabs.com',\n isEvm: false,\n contracts: {\n hub: '0x1a89da9e9f8f0bc90d8d492890bd55fb261c6277d2a95dfcac70c268d0c23dcc',\n wormholeCoreBridge: '0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625',\n tokenBridge: '0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f',\n },\n },\n suiTestnet: {\n name: 'Sui Testnet',\n chainId: 0,\n wormholeChainId: 21,\n rpcUrl: 'https://fullnode.testnet.sui.io:443',\n explorerUrl: 'https://suiscan.xyz/testnet',\n isEvm: false,\n contracts: {\n hub: '0x35e99fdbbc1cde7e093da6f9e758ba2c4a077904bd64caee2fa6db5e6c4e9e37',\n wormholeCoreBridge: '0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790',\n },\n },\n starknetSepolia: {\n name: 'Starknet Sepolia',\n chainId: 0, // Native Starknet chain ID (SN_SEPOLIA = 0x534e5f5345504f4c4941)\n wormholeChainId: 50001, // Custom chain ID (50000+ reserved for non-Wormhole chains)\n rpcUrl: 'https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/tsOnfTBZDKMXcUA26OED-',\n explorerUrl: 'https://sepolia.starkscan.co',\n isEvm: false,\n contracts: {\n // Starknet spoke contract\n hub: '0x68adcc730ed6c355200d00f763825448497b9cdf7936ca121711e078c88e811',\n // Custom bridge contract (NOT Wormhole)\n wormholeCoreBridge: '0x2c458c1ae64556482b05cc2d3ee5b032ed114d68429dda2062c9849a5a725f8',\n },\n // Hub chain ID that Starknet bridge validates (Base Sepolia = 10004)\n hubChainId: 10004,\n },\n};\n\n// ============================================================================\n// Mainnet Chain Configurations\n// ============================================================================\n\nexport const MAINNET_CHAINS: Record<string, ChainConfig> = {\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n wormholeChainId: 2,\n rpcUrl: 'https://eth.llamarpc.com',\n explorerUrl: 'https://etherscan.io',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B',\n tokenBridge: '0x3ee18B2214AFF97000D974cf647E7C347E8fa585',\n },\n },\n base: {\n name: 'Base',\n chainId: 8453,\n wormholeChainId: 30,\n rpcUrl: 'https://mainnet.base.org',\n explorerUrl: 'https://basescan.org',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6',\n tokenBridge: '0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627',\n },\n },\n optimism: {\n name: 'Optimism',\n chainId: 10,\n wormholeChainId: 24,\n rpcUrl: 'https://mainnet.optimism.io',\n explorerUrl: 'https://optimistic.etherscan.io',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722',\n tokenBridge: '0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b',\n },\n },\n arbitrum: {\n name: 'Arbitrum',\n chainId: 42161,\n wormholeChainId: 23,\n rpcUrl: 'https://arb1.arbitrum.io/rpc',\n explorerUrl: 'https://arbiscan.io',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0xa5f208e072434bC67592E4C49C1B991BA79BCA46',\n tokenBridge: '0x0b2402144Bb366A632D14B83F244D2e0e21bD39c',\n },\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n wormholeChainId: 5,\n rpcUrl: 'https://polygon-rpc.com',\n explorerUrl: 'https://polygonscan.com',\n isEvm: true,\n contracts: {\n wormholeCoreBridge: '0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7',\n tokenBridge: '0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE',\n },\n },\n solana: {\n name: 'Solana',\n chainId: 0,\n wormholeChainId: 1,\n rpcUrl: 'https://api.mainnet-beta.solana.com',\n explorerUrl: 'https://explorer.solana.com',\n isEvm: false,\n contracts: {\n wormholeCoreBridge: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth',\n tokenBridge: 'wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb',\n },\n },\n aptos: {\n name: 'Aptos',\n chainId: 0,\n wormholeChainId: 22,\n rpcUrl: 'https://fullnode.mainnet.aptoslabs.com/v1',\n explorerUrl: 'https://explorer.aptoslabs.com',\n isEvm: false,\n contracts: {\n wormholeCoreBridge: '0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625',\n tokenBridge: '0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f',\n },\n },\n sui: {\n name: 'Sui',\n chainId: 0,\n wormholeChainId: 21,\n rpcUrl: 'https://fullnode.mainnet.sui.io:443',\n explorerUrl: 'https://suiscan.xyz/mainnet',\n isEvm: false,\n contracts: {\n wormholeCoreBridge: '0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c',\n },\n },\n};\n\n// ============================================================================\n// Wormhole API Endpoints\n// ============================================================================\n\nexport const WORMHOLE_API = {\n MAINNET: 'https://api.wormholescan.io',\n TESTNET: 'https://api.testnet.wormholescan.io',\n GUARDIAN_RPC_MAINNET: 'https://wormhole-v2-mainnet-api.certus.one',\n GUARDIAN_RPC_TESTNET: 'https://wormhole-v2-testnet-api.certus.one',\n} as const;\n\n// ============================================================================\n// Hub Contract ABI (minimal)\n// ============================================================================\n\nexport const HUB_ABI = [\n 'function authenticateAndDispatch((bytes authenticatorData, string clientDataJSON, uint256 challengeIndex, uint256 typeIndex, uint256 r, uint256 s) auth, uint256 publicKeyX, uint256 publicKeyY, uint16 targetChain, bytes actionPayload) external payable returns (uint64 sequence)',\n 'function authenticateRawAndDispatch(uint256 r, uint256 s, bytes32 messageHash, uint256 publicKeyX, uint256 publicKeyY, uint16 targetChain, bytes actionPayload, uint256 nonce) external payable returns (uint64 sequence)',\n 'function getNonce(bytes32 userKeyHash) external view returns (uint256)',\n 'function encodeTransferAction(address token, address recipient, uint256 amount) external pure returns (bytes)',\n 'function encodeExecuteAction(address target, uint256 value, bytes data) external pure returns (bytes)',\n 'function encodeBridgeAction(bytes32 token, uint256 amount, uint16 targetChain, bytes32 recipient) external pure returns (bytes)',\n 'function messageFee() external view returns (uint256)',\n 'event Dispatched(bytes32 indexed userKeyHash, uint16 targetChain, uint256 nonce, uint64 sequence, bytes actionPayload)',\n] as const;\n\n// ============================================================================\n// Vault Factory ABI (minimal)\n// ============================================================================\n\nexport const VAULT_FACTORY_ABI = [\n 'function createVault(bytes32 userKeyHash) external returns (address)',\n 'function getVault(bytes32 userKeyHash) external view returns (address)',\n 'function vaultExists(bytes32 userKeyHash) external view returns (bool)',\n 'event VaultCreated(bytes32 indexed userKeyHash, address vault)',\n] as const;\n\n// ============================================================================\n// Vault ABI (minimal)\n// ============================================================================\n\nexport const VAULT_ABI = [\n 'function execute(address target, uint256 value, bytes data) external returns (bytes)',\n 'function executeFromHub(bytes32 vaaHash, uint16 emitterChain, bytes32 emitterAddress, bytes payload) external',\n 'function owner() external view returns (bytes32)',\n 'function hub() external view returns (address)',\n 'receive() external payable',\n] as const;\n"],"mappings":"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","names":["hex","AptosSDK"]}
|
|
@@ -207,12 +207,12 @@ var AptosClient = class {
|
|
|
207
207
|
*/
|
|
208
208
|
async getVaultAddress(userKeyHash) {
|
|
209
209
|
try {
|
|
210
|
-
const
|
|
210
|
+
const keyHashBytes = this.hexToBytes(userKeyHash.replace("0x", "").padStart(64, "0"));
|
|
211
211
|
const payload = {
|
|
212
212
|
function: `${this.moduleAddress}::spoke::get_vault_address`,
|
|
213
213
|
type_arguments: [],
|
|
214
|
-
arguments: [
|
|
215
|
-
// Pass as
|
|
214
|
+
arguments: [Array.from(keyHashBytes)]
|
|
215
|
+
// Pass as array of numbers for vector<u8>
|
|
216
216
|
};
|
|
217
217
|
const response = await this.client.view(payload);
|
|
218
218
|
if (response && response.length > 0) {
|