@relayprotocol/relay-svm-wallet-adapter 22.0.4 → 23.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,9 +12,13 @@ const assertBase58TransactionSignature = (signature) => {
12
12
  }
13
13
  };
14
14
  const adaptSolanaWallet = (walletAddress, chainId, connection, signAndSendTransaction, payerKey) => {
15
- let _chainId = chainId;
16
15
  const getChainId = async () => {
17
- return _chainId;
16
+ return chainId;
17
+ };
18
+ const assertBoundChain = (receivedChainId) => {
19
+ if (receivedChainId !== chainId) {
20
+ throw new Error('Cannot switch to an invalid svm chain id');
21
+ }
18
22
  };
19
23
  return {
20
24
  vmType: 'svm',
@@ -25,7 +29,8 @@ const adaptSolanaWallet = (walletAddress, chainId, connection, signAndSendTransa
25
29
  handleSignMessageStep: async () => {
26
30
  throw new Error('Message signing not implemented for Solana');
27
31
  },
28
- handleSendTransactionStep: async (_chainId, stepItem) => {
32
+ handleSendTransactionStep: async (stepChainId, stepItem) => {
33
+ assertBoundChain(stepChainId);
29
34
  const client = (0, relay_sdk_1.getClient)();
30
35
  const instructions = stepItem?.data?.instructions?.map((i) => new web3_js_1.TransactionInstruction({
31
36
  keys: i.keys.map((k) => ({
@@ -46,7 +51,7 @@ const adaptSolanaWallet = (walletAddress, chainId, connection, signAndSendTransa
46
51
  client.log([
47
52
  'Skipping address lookup tables that could not be resolved on the current chain',
48
53
  missingLookupTables,
49
- _chainId
54
+ stepChainId
50
55
  ], relay_sdk_1.LogLevel.Warn);
51
56
  }
52
57
  const messageV0 = new web3_js_1.TransactionMessage({
@@ -63,7 +68,8 @@ const adaptSolanaWallet = (walletAddress, chainId, connection, signAndSendTransa
63
68
  client.log(['Transaction Signature obtained', signature], relay_sdk_1.LogLevel.Verbose);
64
69
  return transactionSignature;
65
70
  },
66
- handleConfirmTransactionStep: async (txHash) => {
71
+ handleConfirmTransactionStep: async (txHash, stepChainId) => {
72
+ assertBoundChain(stepChainId);
67
73
  assertBase58TransactionSignature(txHash);
68
74
  const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash('confirmed');
69
75
  const result = await connection.confirmTransaction({
@@ -80,9 +86,8 @@ const adaptSolanaWallet = (walletAddress, chainId, connection, signAndSendTransa
80
86
  txHash
81
87
  };
82
88
  },
83
- switchChain: (chainId) => {
84
- _chainId = chainId;
85
- return new Promise((res) => res());
89
+ switchChain: async (targetChainId) => {
90
+ assertBoundChain(targetChainId);
86
91
  }
87
92
  };
88
93
  };
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/adapter.ts"],"names":[],"mappings":";;;AAAA,6CASwB;AACxB,wDAKiC;AAEjC,MAAM,sBAAsB,GAAG,yBAAyB,CAAA;AAExD,MAAM,gCAAgC,GAAG,CACvC,SAA2C,EAC3C,EAAE;IACF,IACE,OAAO,SAAS,KAAK,QAAQ;QAC7B,SAAS,CAAC,MAAM,KAAK,CAAC;QACtB,CAAC,sBAAsB,CAAC,IAAI,CAAC,SAAS,CAAC,EACvC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;AACH,CAAC,CAAA;AAWM,MAAM,iBAAiB,GAAG,CAC/B,aAAqB,EACrB,OAAe,EACf,UAAsB,EACtB,sBAOE,EACF,QAAiB,EACF,EAAE;IACjB,IAAI,QAAQ,GAAG,OAAO,CAAA;IACtB,MAAM,UAAU,GAAG,KAAK,IAAI,EAAE;QAC5B,OAAO,QAAQ,CAAA;IACjB,CAAC,CAAA;IAED,OAAO;QACL,MAAM,EAAE,KAAK;QACb,UAAU;QACV,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,OAAO,aAAa,CAAA;QACtB,CAAC;QACD,qBAAqB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;QAC/D,CAAC;QACD,yBAAyB,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE;YACtD,MAAM,MAAM,GAAG,IAAA,qBAAS,GAAE,CAAA;YAE1B,MAAM,YAAY,GAChB,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,CAC/B,CAAC,CAAC,EAAE,EAAE,CACJ,IAAI,gCAAsB,CAAC;gBACzB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACvB,QAAQ,EAAE,CAAC,CAAC,QAAQ;oBACpB,UAAU,EAAE,CAAC,CAAC,UAAU;oBACxB,MAAM,EAAE,IAAI,mBAAS,CAAC,CAAC,CAAC,MAAM,CAAC;iBAChC,CAAC,CAAC;gBACH,SAAS,EAAE,IAAI,mBAAS,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC;aACjC,CAAC,CACL,IAAI,EAAE,CAAA;YAET,MAAM,2BAA2B,GAC/B,QAAQ,EAAE,IAAI,EAAE,2BAA2B,IAAI,EAAE,CAAA;YAEnD,MAAM,oBAAoB,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5C,2BAA2B,CAAC,GAAG,CAAC,CAAC,OAAe,EAAE,EAAE,CAClD,UAAU;iBACP,qBAAqB,CAAC,IAAI,mBAAS,CAAC,OAAO,CAAC,CAAC;iBAC7C,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAC5B,CACF,CAAA;YAQD,MAAM,0BAA0B,GAAG,oBAAoB,CAAC,MAAM,CAC5D,CAAC,KAAK,EAAsC,EAAE,CAAC,KAAK,KAAK,IAAI,CAC9D,CAAA;YAED,MAAM,mBAAmB,GAAG,2BAA2B,CAAC,MAAM,CAC5D,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CACnC,CAAA;YACD,IAAI,mBAAmB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnC,MAAM,CAAC,GAAG,CACR;oBACE,gFAAgF;oBAChF,mBAAmB;oBACnB,QAAQ;iBACT,EACD,oBAAQ,CAAC,IAAI,CACd,CAAA;YACH,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,4BAAkB,CAAC;gBACvC,QAAQ,EAAE,IAAI,mBAAS,CAAC,QAAQ,IAAI,aAAa,CAAC;gBAClD,YAAY;gBACZ,eAAe,EAAE,MAAM,UAAU;qBAC9B,kBAAkB,EAAE;qBACpB,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;aAC5B,CAAC,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,CAAA;YAEjD,MAAM,WAAW,GAAG,IAAI,8BAAoB,CAAC,SAAS,CAAC,CAAA;YACvD,MAAM,SAAS,GAAG,MAAM,sBAAsB,CAC5C,WAAW,EACX,SAAS,EACT,YAAY,EACZ,QAAQ,CAAC,IAAI,CAAC,YAAY,CAC3B,CAAA;YACD,MAAM,oBAAoB,GAAG,SAAS,EAAE,SAAS,CAAA;YACjD,gCAAgC,CAAC,oBAAoB,CAAC,CAAA;YAEtD,MAAM,CAAC,GAAG,CACR,CAAC,gCAAgC,EAAE,SAAS,CAAC,EAC7C,oBAAQ,CAAC,OAAO,CACjB,CAAA;YAED,OAAO,oBAAoB,CAAA;QAC7B,CAAC;QACD,4BAA4B,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAG7C,gCAAgC,CAAC,MAAM,CAAC,CAAA;YAExC,MAAM,EAAE,SAAS,EAAE,oBAAoB,EAAE,GACvC,MAAM,UAAU,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAA;YAElD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,kBAAkB,CAAC;gBACjD,SAAS,EAAE,SAAS;gBACpB,oBAAoB,EAAE,oBAAoB;gBAC1C,SAAS,EAAE,MAAM;aAClB,CAAC,CAAA;YAEF,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAA;YAC5D,CAAC;YAED,OAAO;gBACL,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE;gBACzC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI;gBAChC,MAAM;aACP,CAAA;QACH,CAAC;QACD,WAAW,EAAE,CAAC,OAAe,EAAE,EAAE;YAC/B,QAAQ,GAAG,OAAO,CAAA;YAClB,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAA;QACpC,CAAC;KACF,CAAA;AACH,CAAC,CAAA;AAtIY,QAAA,iBAAiB,qBAsI7B","sourcesContent":["import {\n AddressLookupTableAccount,\n Connection,\n PublicKey,\n TransactionInstruction,\n TransactionMessage,\n VersionedTransaction,\n type SendOptions,\n type TransactionSignature\n} from '@solana/web3.js'\nimport {\n LogLevel,\n getClient,\n type AdaptedWallet,\n type TransactionStepItem\n} from '@relayprotocol/relay-sdk'\n\nconst BASE58_SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]+$/\n\nconst assertBase58TransactionSignature = (\n signature: TransactionSignature | undefined\n) => {\n if (\n typeof signature !== 'string' ||\n signature.length === 0 ||\n !BASE58_SIGNATURE_REGEX.test(signature)\n ) {\n throw new Error('Invalid Solana signature: expected base58.')\n }\n}\n\n/**\n * Adapts a Solana wallet to work with the Relay SDK\n * @param walletAddress - The public key address of the Solana wallet\n * @param chainId - The chain ID for the Solana network (Relay uses 792703809)\n * @param connection - The Solana web3.js Connection instance for interacting with the network\n * @param signAndSendTransaction - Function to sign and send a transaction, returning a promise with a base58 encoded transaction signature\n * @param payerKey - Optional public key of the account that will pay for transaction fees (defaults to walletAddress)\n * @returns An AdaptedWallet object that conforms to the Relay SDK interface\n */\nexport const adaptSolanaWallet = (\n walletAddress: string,\n chainId: number,\n connection: Connection,\n signAndSendTransaction: (\n transaction: VersionedTransaction,\n options?: SendOptions,\n instructions?: TransactionInstruction[],\n rawInstructions?: TransactionStepItem['data']['instructions']\n ) => Promise<{\n signature: TransactionSignature\n }>,\n payerKey?: string\n): AdaptedWallet => {\n let _chainId = chainId\n const getChainId = async () => {\n return _chainId\n }\n\n return {\n vmType: 'svm',\n getChainId,\n address: async () => {\n return walletAddress\n },\n handleSignMessageStep: async () => {\n throw new Error('Message signing not implemented for Solana')\n },\n handleSendTransactionStep: async (_chainId, stepItem) => {\n const client = getClient()\n\n const instructions =\n stepItem?.data?.instructions?.map(\n (i) =>\n new TransactionInstruction({\n keys: i.keys.map((k) => ({\n isSigner: k.isSigner,\n isWritable: k.isWritable,\n pubkey: new PublicKey(k.pubkey)\n })),\n programId: new PublicKey(i.programId),\n data: Buffer.from(i.data, 'hex')\n })\n ) ?? []\n\n const addressLookupTableAddresses =\n stepItem?.data?.addressLookupTableAddresses ?? []\n\n const resolvedLookupTables = await Promise.all(\n addressLookupTableAddresses.map((address: string) =>\n connection\n .getAddressLookupTable(new PublicKey(address))\n .then((res) => res.value)\n )\n )\n\n // A lookup table address returned by the API may not exist on the\n // connected chain (e.g. a Solana mainnet table referenced in an Eclipse\n // swap). Passing null into compileToV0Message crashes in\n // extractTableLookup before the wallet ever prompts, so skip any table\n // that can't be resolved and compile without it — lookup tables only\n // compress the message, the transaction is still valid without them.\n const addressLookupTableAccounts = resolvedLookupTables.filter(\n (table): table is AddressLookupTableAccount => table !== null\n )\n\n const missingLookupTables = addressLookupTableAddresses.filter(\n (_, i) => !resolvedLookupTables[i]\n )\n if (missingLookupTables.length > 0) {\n client.log(\n [\n 'Skipping address lookup tables that could not be resolved on the current chain',\n missingLookupTables,\n _chainId\n ],\n LogLevel.Warn\n )\n }\n\n const messageV0 = new TransactionMessage({\n payerKey: new PublicKey(payerKey ?? walletAddress),\n instructions,\n recentBlockhash: await connection\n .getLatestBlockhash()\n .then((b) => b.blockhash)\n }).compileToV0Message(addressLookupTableAccounts)\n\n const transaction = new VersionedTransaction(messageV0)\n const signature = await signAndSendTransaction(\n transaction,\n undefined,\n instructions,\n stepItem.data.instructions\n )\n const transactionSignature = signature?.signature\n assertBase58TransactionSignature(transactionSignature)\n\n client.log(\n ['Transaction Signature obtained', signature],\n LogLevel.Verbose\n )\n\n return transactionSignature\n },\n handleConfirmTransactionStep: async (txHash) => {\n // Solana doesn't have a concept of replaced transactions\n // So we don't need to handle onReplaced and onCancelled\n assertBase58TransactionSignature(txHash)\n\n const { blockhash, lastValidBlockHeight } =\n await connection.getLatestBlockhash('confirmed')\n\n const result = await connection.confirmTransaction({\n blockhash: blockhash,\n lastValidBlockHeight: lastValidBlockHeight,\n signature: txHash\n })\n\n if (result.value.err) {\n throw new Error(`Transaction failed: ${result.value.err}`)\n }\n\n return {\n blockHash: result.context.slot.toString(),\n blockNumber: result.context.slot,\n txHash\n }\n },\n switchChain: (chainId: number) => {\n _chainId = chainId\n return new Promise((res) => res())\n }\n }\n}\n"]}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AddressLookupTableAccount,\n Connection,\n PublicKey,\n TransactionInstruction,\n TransactionMessage,\n VersionedTransaction,\n type SendOptions,\n type TransactionSignature\n} from '@solana/web3.js'\nimport {\n LogLevel,\n getClient,\n type AdaptedWallet,\n type TransactionStepItem\n} from '@relayprotocol/relay-sdk'\n\nconst BASE58_SIGNATURE_REGEX = /^[1-9A-HJ-NP-Za-km-z]+$/\n\nconst assertBase58TransactionSignature = (\n signature: TransactionSignature | undefined\n) => {\n if (\n typeof signature !== 'string' ||\n signature.length === 0 ||\n !BASE58_SIGNATURE_REGEX.test(signature)\n ) {\n throw new Error('Invalid Solana signature: expected base58.')\n }\n}\n\n/**\n * Adapts a Solana wallet to work with the Relay SDK\n * @param walletAddress - The public key address of the Solana wallet\n * @param chainId - The Relay chain ID of the SVM network the connection points to (e.g. 792703809 for Solana, 9286185 for Eclipse)\n * @param connection - The Solana web3.js Connection instance for that network; the adapter is bound to it and cannot switch to another SVM chain\n * @param signAndSendTransaction - Function to sign and send a transaction, returning a promise with a base58 encoded transaction signature\n * @param payerKey - Optional public key of the account that will pay for transaction fees (defaults to walletAddress)\n * @returns An AdaptedWallet object that conforms to the Relay SDK interface\n */\nexport const adaptSolanaWallet = (\n walletAddress: string,\n chainId: number,\n connection: Connection,\n signAndSendTransaction: (\n transaction: VersionedTransaction,\n options?: SendOptions,\n instructions?: TransactionInstruction[],\n rawInstructions?: TransactionStepItem['data']['instructions']\n ) => Promise<{\n signature: TransactionSignature\n }>,\n payerKey?: string\n): AdaptedWallet => {\n const getChainId = async () => {\n return chainId\n }\n\n const assertBoundChain = (receivedChainId: number) => {\n if (receivedChainId !== chainId) {\n throw new Error('Cannot switch to an invalid svm chain id')\n }\n }\n\n return {\n vmType: 'svm',\n getChainId,\n address: async () => {\n return walletAddress\n },\n handleSignMessageStep: async () => {\n throw new Error('Message signing not implemented for Solana')\n },\n handleSendTransactionStep: async (stepChainId, stepItem) => {\n assertBoundChain(stepChainId)\n const client = getClient()\n\n const instructions =\n stepItem?.data?.instructions?.map(\n (i) =>\n new TransactionInstruction({\n keys: i.keys.map((k) => ({\n isSigner: k.isSigner,\n isWritable: k.isWritable,\n pubkey: new PublicKey(k.pubkey)\n })),\n programId: new PublicKey(i.programId),\n data: Buffer.from(i.data, 'hex')\n })\n ) ?? []\n\n const addressLookupTableAddresses =\n stepItem?.data?.addressLookupTableAddresses ?? []\n\n const resolvedLookupTables = await Promise.all(\n addressLookupTableAddresses.map((address: string) =>\n connection\n .getAddressLookupTable(new PublicKey(address))\n .then((res) => res.value)\n )\n )\n\n // A lookup table address returned by the API may not exist on the\n // connected chain (e.g. a Solana mainnet table referenced in an Eclipse\n // swap). Passing null into compileToV0Message crashes in\n // extractTableLookup before the wallet ever prompts, so skip any table\n // that can't be resolved and compile without it — lookup tables only\n // compress the message, the transaction is still valid without them.\n const addressLookupTableAccounts = resolvedLookupTables.filter(\n (table): table is AddressLookupTableAccount => table !== null\n )\n\n const missingLookupTables = addressLookupTableAddresses.filter(\n (_, i) => !resolvedLookupTables[i]\n )\n if (missingLookupTables.length > 0) {\n client.log(\n [\n 'Skipping address lookup tables that could not be resolved on the current chain',\n missingLookupTables,\n stepChainId\n ],\n LogLevel.Warn\n )\n }\n\n const messageV0 = new TransactionMessage({\n payerKey: new PublicKey(payerKey ?? walletAddress),\n instructions,\n recentBlockhash: await connection\n .getLatestBlockhash()\n .then((b) => b.blockhash)\n }).compileToV0Message(addressLookupTableAccounts)\n\n const transaction = new VersionedTransaction(messageV0)\n const signature = await signAndSendTransaction(\n transaction,\n undefined,\n instructions,\n stepItem.data.instructions\n )\n const transactionSignature = signature?.signature\n assertBase58TransactionSignature(transactionSignature)\n\n client.log(\n ['Transaction Signature obtained', signature],\n LogLevel.Verbose\n )\n\n return transactionSignature\n },\n handleConfirmTransactionStep: async (txHash, stepChainId) => {\n // Solana doesn't have a concept of replaced transactions\n // So we don't need to handle onReplaced and onCancelled\n assertBoundChain(stepChainId)\n assertBase58TransactionSignature(txHash)\n\n const { blockhash, lastValidBlockHeight } =\n await connection.getLatestBlockhash('confirmed')\n\n const result = await connection.confirmTransaction({\n blockhash: blockhash,\n lastValidBlockHeight: lastValidBlockHeight,\n signature: txHash\n })\n\n if (result.value.err) {\n throw new Error(`Transaction failed: ${result.value.err}`)\n }\n\n return {\n blockHash: result.context.slot.toString(),\n blockNumber: result.context.slot,\n txHash\n }\n },\n // The connection fixes the SVM cluster, so only a no-op switch is safe.\n switchChain: async (targetChainId: number) => {\n assertBoundChain(targetChainId)\n }\n }\n}\n"]}