@account-kit/signer 4.25.1 → 4.27.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.
@@ -9,3 +9,4 @@ export { AlchemyWebSigner } from "./signer.js";
9
9
  export type * from "./solanaSigner.js";
10
10
  export type * from "./types.js";
11
11
  export { AlchemySignerStatus } from "./types.js";
12
+ export { SolanaSigner } from "./solanaSigner.js";
package/dist/esm/index.js CHANGED
@@ -5,4 +5,5 @@ export { NotAuthenticatedError, OAuthProvidersError, MfaRequiredError, } from ".
5
5
  export { DEFAULT_SESSION_MS, SessionManagerParamsSchema, } from "./session/manager.js";
6
6
  export { AlchemyWebSigner } from "./signer.js";
7
7
  export { AlchemySignerStatus } from "./types.js";
8
+ export { SolanaSigner } from "./solanaSigner.js";
8
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { BaseAlchemySigner } from \"./base.js\";\nexport { BaseSignerClient } from \"./client/base.js\";\nexport {\n AlchemySignerWebClient,\n OauthCancelledError,\n OauthFailedError,\n} from \"./client/index.js\";\nexport type * from \"./client/types.js\";\nexport {\n NotAuthenticatedError,\n OAuthProvidersError,\n MfaRequiredError,\n} from \"./errors.js\";\nexport {\n DEFAULT_SESSION_MS,\n SessionManagerParamsSchema,\n} from \"./session/manager.js\";\nexport type * from \"./signer.js\";\nexport { AlchemyWebSigner } from \"./signer.js\";\nexport type * from \"./solanaSigner.js\";\nexport type * from \"./types.js\";\nexport { AlchemySignerStatus } from \"./types.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["export { BaseAlchemySigner } from \"./base.js\";\nexport { BaseSignerClient } from \"./client/base.js\";\nexport {\n AlchemySignerWebClient,\n OauthCancelledError,\n OauthFailedError,\n} from \"./client/index.js\";\nexport type * from \"./client/types.js\";\nexport {\n NotAuthenticatedError,\n OAuthProvidersError,\n MfaRequiredError,\n} from \"./errors.js\";\nexport {\n DEFAULT_SESSION_MS,\n SessionManagerParamsSchema,\n} from \"./session/manager.js\";\nexport type * from \"./signer.js\";\nexport { AlchemyWebSigner } from \"./signer.js\";\nexport type * from \"./solanaSigner.js\";\nexport type * from \"./types.js\";\nexport { AlchemySignerStatus } from \"./types.js\";\nexport { SolanaSigner } from \"./solanaSigner.js\";\n"]}
@@ -1,12 +1,45 @@
1
- import { Transaction, type VersionedTransaction } from "@solana/web3.js";
1
+ import { Connection, Transaction, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
2
2
  import { type ByteArray } from "viem";
3
3
  import type { BaseSignerClient } from "./client/base";
4
+ /**
5
+ * The SolanaSigner class is used to sign transactions and messages for the Solana blockchain.
6
+ * It provides methods to add signatures to transactions and sign messages.
7
+ */
4
8
  export declare class SolanaSigner {
5
- private alchemyClient;
6
- address: string;
9
+ readonly alchemyClient: BaseSignerClient;
10
+ readonly address: string;
11
+ /**
12
+ * Constructor for the SolanaSigner class which is a wrapper around the alchemy client, and is more focused on the solana web3
13
+ *
14
+ * @param {object} client This is the client that will be used to sign the transaction, and we are just having functions on top of it.
15
+ */
7
16
  constructor(client: BaseSignerClient);
8
- addSignature(tx: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
17
+ /**
18
+ * Adds a signature of the client user to a transaction
19
+ *
20
+ * @param {Transaction | VersionedTransaction} transaction - The transaction to add the signature to
21
+ * @returns {Promise<Transaction | VersionedTransaction >} The transaction with the signature added
22
+ */
23
+ addSignature(transaction: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
24
+ /**
25
+ * Signs a message
26
+ *
27
+ * @param {Uint8Array} message - The message to sign
28
+ * @returns {Promise<ByteArray>} The signature of the message
29
+ */
9
30
  signMessage(message: Uint8Array): Promise<ByteArray>;
31
+ createTransfer(instructions: TransactionInstruction[], connection: Connection, version?: "versioned"): Promise<VersionedTransaction>;
32
+ createTransfer(instructions: TransactionInstruction[], connection: Connection, version?: "legacy"): Promise<Transaction>;
33
+ createTransfer(instructions: TransactionInstruction[], connection: Connection): Promise<VersionedTransaction>;
34
+ /**
35
+ * Adds sponsorship to a transaction. Used to have a party like Alchemy pay for the transaction.
36
+ *
37
+ * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction
38
+ * @param {Connection} connection - The connection to use for the transaction
39
+ * @param {string} [policyId] - The policy ID to add sponsorship to
40
+ * @returns {Promise<VersionedTransaction>} The transaction with sponsorship added
41
+ */
42
+ addSponsorship(instructions: TransactionInstruction[], connection: Connection, policyId: string): Promise<VersionedTransaction>;
10
43
  private formatSignatureForSolana;
11
44
  private getMessageToSign;
12
45
  }
@@ -1,8 +1,16 @@
1
- import { PublicKey, Transaction, } from "@solana/web3.js";
1
+ import { Connection, PublicKey, Transaction, TransactionInstruction, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
2
2
  import { size, slice, toBytes, toHex } from "viem";
3
3
  import { NotAuthenticatedError } from "./errors.js";
4
- // TODO: I don't want this to be a class so that the flow is closer to how we do this for `toViemAccount`
4
+ /**
5
+ * The SolanaSigner class is used to sign transactions and messages for the Solana blockchain.
6
+ * It provides methods to add signatures to transactions and sign messages.
7
+ */
5
8
  export class SolanaSigner {
9
+ /**
10
+ * Constructor for the SolanaSigner class which is a wrapper around the alchemy client, and is more focused on the solana web3
11
+ *
12
+ * @param {object} client This is the client that will be used to sign the transaction, and we are just having functions on top of it.
13
+ */
6
14
  constructor(client) {
7
15
  Object.defineProperty(this, "alchemyClient", {
8
16
  enumerable: true,
@@ -22,7 +30,13 @@ export class SolanaSigner {
22
30
  // TODO: also throw here
23
31
  this.address = client.getUser().solanaAddress;
24
32
  }
25
- async addSignature(tx) {
33
+ /**
34
+ * Adds a signature of the client user to a transaction
35
+ *
36
+ * @param {Transaction | VersionedTransaction} transaction - The transaction to add the signature to
37
+ * @returns {Promise<Transaction | VersionedTransaction >} The transaction with the signature added
38
+ */
39
+ async addSignature(transaction) {
26
40
  const user = this.alchemyClient.getUser();
27
41
  if (!user) {
28
42
  throw new NotAuthenticatedError();
@@ -31,11 +45,17 @@ export class SolanaSigner {
31
45
  throw new Error("no solana address");
32
46
  }
33
47
  const fromKey = new PublicKey(user.solanaAddress);
34
- const messageToSign = this.getMessageToSign(tx);
48
+ const messageToSign = this.getMessageToSign(transaction);
35
49
  const signature = await this.alchemyClient.signRawMessage(messageToSign, "SOLANA");
36
- tx.addSignature(fromKey, Buffer.from(toBytes(this.formatSignatureForSolana(signature))));
37
- return tx;
50
+ transaction.addSignature(fromKey, Buffer.from(toBytes(this.formatSignatureForSolana(signature))));
51
+ return transaction;
38
52
  }
53
+ /**
54
+ * Signs a message
55
+ *
56
+ * @param {Uint8Array} message - The message to sign
57
+ * @returns {Promise<ByteArray>} The signature of the message
58
+ */
39
59
  async signMessage(message) {
40
60
  const user = this.alchemyClient.getUser();
41
61
  if (!user) {
@@ -48,6 +68,84 @@ export class SolanaSigner {
48
68
  const signature = await this.alchemyClient.signRawMessage(messageToSign, "SOLANA");
49
69
  return toBytes(this.formatSignatureForSolana(signature));
50
70
  }
71
+ /**
72
+ * Creates a transfer transaction. Used for the SolanaCard example.
73
+ *
74
+ * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction
75
+ * @param {Connection} connection - The connection to use for the transaction
76
+ * @param {"versioned" | "legacy"} [version] - The version of the transaction
77
+ * @returns {Promise<Transaction | VersionedTransaction>} The transfer transaction
78
+ */
79
+ async createTransfer(instructions, connection, version) {
80
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
81
+ let transferTransaction;
82
+ if (version === "legacy") {
83
+ // Legacy transaction
84
+ transferTransaction = instructions.reduce((tx, instruction) => tx.add(instruction), new Transaction());
85
+ // Get a recent block hash
86
+ transferTransaction.recentBlockhash = blockhash;
87
+ // Set the signer
88
+ transferTransaction.feePayer = new PublicKey(this.address);
89
+ }
90
+ else {
91
+ // VersionedTransaction
92
+ const txMessage = new TransactionMessage({
93
+ payerKey: new PublicKey(this.address),
94
+ recentBlockhash: blockhash,
95
+ instructions,
96
+ });
97
+ const versionedTxMessage = txMessage.compileToV0Message();
98
+ transferTransaction = new VersionedTransaction(versionedTxMessage);
99
+ }
100
+ return transferTransaction;
101
+ }
102
+ /**
103
+ * Adds sponsorship to a transaction. Used to have a party like Alchemy pay for the transaction.
104
+ *
105
+ * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction
106
+ * @param {Connection} connection - The connection to use for the transaction
107
+ * @param {string} [policyId] - The policy ID to add sponsorship to
108
+ * @returns {Promise<VersionedTransaction>} The transaction with sponsorship added
109
+ */
110
+ async addSponsorship(instructions, connection, policyId) {
111
+ const { blockhash } = await connection.getLatestBlockhash({
112
+ commitment: "finalized",
113
+ });
114
+ const message = new TransactionMessage({
115
+ // Right now the backend will rewrite this payer Key to the server's address
116
+ payerKey: new PublicKey(this.address),
117
+ recentBlockhash: blockhash,
118
+ instructions,
119
+ }).compileToV0Message();
120
+ const versionedTransaction = new VersionedTransaction(message);
121
+ const serializedTransaction = Buffer.from(versionedTransaction.serialize()).toString("base64");
122
+ const body = JSON.stringify({
123
+ id: crypto?.randomUUID() ?? Math.floor(Math.random() * 1000000),
124
+ jsonrpc: "2.0",
125
+ method: "alchemy_requestFeePayer",
126
+ params: [
127
+ {
128
+ policyId,
129
+ serializedTransaction,
130
+ },
131
+ ],
132
+ });
133
+ const options = {
134
+ method: "POST",
135
+ headers: {
136
+ accept: "application/json",
137
+ "content-type": "application/json",
138
+ },
139
+ body,
140
+ };
141
+ const response = await fetch(
142
+ // TODO: Use the connection??
143
+ connection.rpcEndpoint, options);
144
+ const jsonResponse = await response.json();
145
+ if (!jsonResponse?.result?.serializedTransaction)
146
+ throw new Error(`Response doesn't include the serializedTransaction ${JSON.stringify(jsonResponse)}`);
147
+ return VersionedTransaction.deserialize(decodeBase64(jsonResponse.result.serializedTransaction));
148
+ }
51
149
  formatSignatureForSolana(signature) {
52
150
  if (size(signature) === 64)
53
151
  return signature;
@@ -64,4 +162,7 @@ export class SolanaSigner {
64
162
  return toHex(messageToSign);
65
163
  }
66
164
  }
165
+ function decodeBase64(serializedTransaction) {
166
+ return Buffer.from(serializedTransaction, "base64");
167
+ }
67
168
  //# sourceMappingURL=solanaSigner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"solanaSigner.js","sourceRoot":"","sources":["../../src/solanaSigner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,WAAW,GAEZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAA4B,MAAM,MAAM,CAAC;AAE7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,yGAAyG;AACzG,MAAM,OAAO,YAAY;IAIvB,YAAY,MAAwB;QAH5B;;;;;WAAgC;QACjC;;;;;WAAgB;QAGrB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAEjE,wBAAwB;QACxB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,EAAG,CAAC,aAAc,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,YAAY,CAChB,EAAsC;QAEtC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,qBAAqB,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CACvD,aAAa,EACb,QAAQ,CACT,CAAC;QAEF,EAAE,CAAC,YAAY,CACb,OAAO,EACP,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC,CAAC,CAC/D,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAmB;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,qBAAqB,EAAE,CAAC;QACpC,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,MAAM,aAAa,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CACvD,aAAa,EACb,QAAQ,CACT,CAAC;QAEF,OAAO,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC3D,CAAC;IAEO,wBAAwB,CAAC,SAAc;QAC7C,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;YAAE,OAAO,SAAS,CAAC;QAE7C,OAAO,KAAK,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACjC,CAAC;IAEO,gBAAgB,CAAC,EAAsC;QAC7D,IAAI,aAAa,CAAC;QAClB,IAAI,EAAE,YAAY,WAAW,EAAE,CAAC;YAC9B,aAAa,GAAG,EAAE,CAAC,gBAAgB,EAAE,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,KAAK,CAAC,aAAa,CAAC,CAAC;IAC9B,CAAC;CACF","sourcesContent":["import {\n PublicKey,\n Transaction,\n type VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { size, slice, toBytes, toHex, type ByteArray, type Hex } from \"viem\";\nimport type { BaseSignerClient } from \"./client/base\";\nimport { NotAuthenticatedError } from \"./errors.js\";\n\n// TODO: I don't want this to be a class so that the flow is closer to how we do this for `toViemAccount`\nexport class SolanaSigner {\n private alchemyClient: BaseSignerClient;\n public address: string;\n\n constructor(client: BaseSignerClient) {\n this.alchemyClient = client;\n if (!client.getUser()) throw new Error(\"Must be authenticated!\");\n\n // TODO: also throw here\n this.address = client.getUser()!.solanaAddress!;\n }\n\n async addSignature(\n tx: Transaction | VersionedTransaction\n ): Promise<Transaction | VersionedTransaction> {\n const user = this.alchemyClient.getUser();\n if (!user) {\n throw new NotAuthenticatedError();\n }\n\n if (!user.solanaAddress) {\n throw new Error(\"no solana address\");\n }\n\n const fromKey = new PublicKey(user.solanaAddress);\n const messageToSign = this.getMessageToSign(tx);\n const signature = await this.alchemyClient.signRawMessage(\n messageToSign,\n \"SOLANA\"\n );\n\n tx.addSignature(\n fromKey,\n Buffer.from(toBytes(this.formatSignatureForSolana(signature)))\n );\n return tx;\n }\n\n async signMessage(message: Uint8Array): Promise<ByteArray> {\n const user = this.alchemyClient.getUser();\n if (!user) {\n throw new NotAuthenticatedError();\n }\n\n if (!user.solanaAddress) {\n throw new Error(\"no solana address\");\n }\n\n const messageToSign = toHex(message);\n const signature = await this.alchemyClient.signRawMessage(\n messageToSign,\n \"SOLANA\"\n );\n\n return toBytes(this.formatSignatureForSolana(signature));\n }\n\n private formatSignatureForSolana(signature: Hex): Hex {\n if (size(signature) === 64) return signature;\n\n return slice(signature, 0, 64);\n }\n\n private getMessageToSign(tx: Transaction | VersionedTransaction): Hex {\n let messageToSign;\n if (tx instanceof Transaction) {\n messageToSign = tx.serializeMessage();\n } else {\n messageToSign = Buffer.from(tx.message.serialize());\n }\n return toHex(messageToSign);\n }\n}\n"]}
1
+ {"version":3,"file":"solanaSigner.js","sourceRoot":"","sources":["../../src/solanaSigner.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Connection,\n PublicKey,\n Transaction,\n TransactionInstruction,\n TransactionMessage,\n VersionedTransaction,\n} from \"@solana/web3.js\";\nimport { size, slice, toBytes, toHex, type ByteArray, type Hex } from \"viem\";\nimport type { BaseSignerClient } from \"./client/base\";\nimport { NotAuthenticatedError } from \"./errors.js\";\n\n/**\n * The SolanaSigner class is used to sign transactions and messages for the Solana blockchain.\n * It provides methods to add signatures to transactions and sign messages.\n */\nexport class SolanaSigner {\n readonly alchemyClient: BaseSignerClient;\n public readonly address: string;\n\n /**\n * Constructor for the SolanaSigner class which is a wrapper around the alchemy client, and is more focused on the solana web3\n *\n * @param {object} client This is the client that will be used to sign the transaction, and we are just having functions on top of it.\n */\n constructor(client: BaseSignerClient) {\n this.alchemyClient = client;\n if (!client.getUser()) throw new Error(\"Must be authenticated!\");\n\n // TODO: also throw here\n this.address = client.getUser()!.solanaAddress!;\n }\n\n /**\n * Adds a signature of the client user to a transaction\n *\n * @param {Transaction | VersionedTransaction} transaction - The transaction to add the signature to\n * @returns {Promise<Transaction | VersionedTransaction >} The transaction with the signature added\n */\n async addSignature(\n transaction: Transaction | VersionedTransaction\n ): Promise<Transaction | VersionedTransaction> {\n const user = this.alchemyClient.getUser();\n if (!user) {\n throw new NotAuthenticatedError();\n }\n\n if (!user.solanaAddress) {\n throw new Error(\"no solana address\");\n }\n\n const fromKey = new PublicKey(user.solanaAddress);\n const messageToSign = this.getMessageToSign(transaction);\n const signature = await this.alchemyClient.signRawMessage(\n messageToSign,\n \"SOLANA\"\n );\n\n transaction.addSignature(\n fromKey,\n Buffer.from(toBytes(this.formatSignatureForSolana(signature)))\n );\n return transaction;\n }\n\n /**\n * Signs a message\n *\n * @param {Uint8Array} message - The message to sign\n * @returns {Promise<ByteArray>} The signature of the message\n */\n async signMessage(message: Uint8Array): Promise<ByteArray> {\n const user = this.alchemyClient.getUser();\n if (!user) {\n throw new NotAuthenticatedError();\n }\n\n if (!user.solanaAddress) {\n throw new Error(\"no solana address\");\n }\n\n const messageToSign = toHex(message);\n const signature = await this.alchemyClient.signRawMessage(\n messageToSign,\n \"SOLANA\"\n );\n\n return toBytes(this.formatSignatureForSolana(signature));\n }\n\n async createTransfer(\n instructions: TransactionInstruction[],\n connection: Connection,\n version?: \"versioned\"\n ): Promise<VersionedTransaction>;\n async createTransfer(\n instructions: TransactionInstruction[],\n connection: Connection,\n version?: \"legacy\"\n ): Promise<Transaction>;\n async createTransfer(\n instructions: TransactionInstruction[],\n connection: Connection\n ): Promise<VersionedTransaction>;\n\n /**\n * Creates a transfer transaction. Used for the SolanaCard example.\n *\n * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction\n * @param {Connection} connection - The connection to use for the transaction\n * @param {\"versioned\" | \"legacy\"} [version] - The version of the transaction\n * @returns {Promise<Transaction | VersionedTransaction>} The transfer transaction\n */\n async createTransfer(\n instructions: TransactionInstruction[],\n connection: Connection,\n version?: string\n ): Promise<Transaction | VersionedTransaction> {\n const blockhash = (await connection.getLatestBlockhash()).blockhash;\n\n let transferTransaction;\n\n if (version === \"legacy\") {\n // Legacy transaction\n transferTransaction = instructions.reduce(\n (tx, instruction) => tx.add(instruction),\n new Transaction()\n );\n\n // Get a recent block hash\n transferTransaction.recentBlockhash = blockhash;\n // Set the signer\n transferTransaction.feePayer = new PublicKey(this.address);\n } else {\n // VersionedTransaction\n const txMessage = new TransactionMessage({\n payerKey: new PublicKey(this.address),\n recentBlockhash: blockhash,\n instructions,\n });\n\n const versionedTxMessage = txMessage.compileToV0Message();\n transferTransaction = new VersionedTransaction(versionedTxMessage);\n }\n\n return transferTransaction;\n }\n\n /**\n * Adds sponsorship to a transaction. Used to have a party like Alchemy pay for the transaction.\n *\n * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction\n * @param {Connection} connection - The connection to use for the transaction\n * @param {string} [policyId] - The policy ID to add sponsorship to\n * @returns {Promise<VersionedTransaction>} The transaction with sponsorship added\n */\n async addSponsorship(\n instructions: TransactionInstruction[],\n connection: Connection,\n policyId: string\n ): Promise<VersionedTransaction> {\n const { blockhash } = await connection.getLatestBlockhash({\n commitment: \"finalized\",\n });\n const message = new TransactionMessage({\n // Right now the backend will rewrite this payer Key to the server's address\n payerKey: new PublicKey(this.address),\n recentBlockhash: blockhash,\n instructions,\n }).compileToV0Message();\n const versionedTransaction = new VersionedTransaction(message);\n const serializedTransaction = Buffer.from(\n versionedTransaction.serialize()\n ).toString(\"base64\");\n const body = JSON.stringify({\n id: crypto?.randomUUID() ?? Math.floor(Math.random() * 1000000),\n jsonrpc: \"2.0\",\n method: \"alchemy_requestFeePayer\",\n params: [\n {\n policyId,\n serializedTransaction,\n },\n ],\n });\n const options = {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n },\n body,\n };\n\n const response = await fetch(\n // TODO: Use the connection??\n connection.rpcEndpoint,\n options\n );\n const jsonResponse = await response.json();\n if (!jsonResponse?.result?.serializedTransaction)\n throw new Error(\n `Response doesn't include the serializedTransaction ${JSON.stringify(\n jsonResponse\n )}`\n );\n return VersionedTransaction.deserialize(\n decodeBase64(jsonResponse.result.serializedTransaction)\n );\n }\n\n private formatSignatureForSolana(signature: Hex): Hex {\n if (size(signature) === 64) return signature;\n\n return slice(signature, 0, 64);\n }\n\n private getMessageToSign(tx: Transaction | VersionedTransaction): Hex {\n let messageToSign;\n if (tx instanceof Transaction) {\n messageToSign = tx.serializeMessage();\n } else {\n messageToSign = Buffer.from(tx.message.serialize());\n }\n return toHex(messageToSign);\n }\n}\nfunction decodeBase64(serializedTransaction: string): Uint8Array {\n return Buffer.from(serializedTransaction, \"base64\");\n}\n"]}
@@ -1 +1 @@
1
- export declare const VERSION = "4.25.1";
1
+ export declare const VERSION = "4.27.0";
@@ -1,4 +1,4 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.25.1";
3
+ export const VERSION = "4.27.0";
4
4
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yBAAyB;AACzB,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC","sourcesContent":["// This file is autogenerated by inject-version.ts. Any changes will be\n// overwritten on commit!\nexport const VERSION = \"4.25.1\";\n"]}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yBAAyB;AACzB,MAAM,CAAC,MAAM,OAAO,GAAG,QAAQ,CAAC","sourcesContent":["// This file is autogenerated by inject-version.ts. Any changes will be\n// overwritten on commit!\nexport const VERSION = \"4.27.0\";\n"]}
@@ -9,4 +9,5 @@ export { AlchemyWebSigner } from "./signer.js";
9
9
  export type * from "./solanaSigner.js";
10
10
  export type * from "./types.js";
11
11
  export { AlchemySignerStatus } from "./types.js";
12
+ export { SolanaSigner } from "./solanaSigner.js";
12
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,mBAAmB,mBAAmB,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,mBAAmB,aAAa,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,YAAY,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAC3B,mBAAmB,mBAAmB,CAAC;AACvC,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,kBAAkB,EAClB,0BAA0B,GAC3B,MAAM,sBAAsB,CAAC;AAC9B,mBAAmB,aAAa,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,YAAY,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,12 +1,45 @@
1
- import { Transaction, type VersionedTransaction } from "@solana/web3.js";
1
+ import { Connection, Transaction, TransactionInstruction, VersionedTransaction } from "@solana/web3.js";
2
2
  import { type ByteArray } from "viem";
3
3
  import type { BaseSignerClient } from "./client/base";
4
+ /**
5
+ * The SolanaSigner class is used to sign transactions and messages for the Solana blockchain.
6
+ * It provides methods to add signatures to transactions and sign messages.
7
+ */
4
8
  export declare class SolanaSigner {
5
- private alchemyClient;
6
- address: string;
9
+ readonly alchemyClient: BaseSignerClient;
10
+ readonly address: string;
11
+ /**
12
+ * Constructor for the SolanaSigner class which is a wrapper around the alchemy client, and is more focused on the solana web3
13
+ *
14
+ * @param {object} client This is the client that will be used to sign the transaction, and we are just having functions on top of it.
15
+ */
7
16
  constructor(client: BaseSignerClient);
8
- addSignature(tx: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
17
+ /**
18
+ * Adds a signature of the client user to a transaction
19
+ *
20
+ * @param {Transaction | VersionedTransaction} transaction - The transaction to add the signature to
21
+ * @returns {Promise<Transaction | VersionedTransaction >} The transaction with the signature added
22
+ */
23
+ addSignature(transaction: Transaction | VersionedTransaction): Promise<Transaction | VersionedTransaction>;
24
+ /**
25
+ * Signs a message
26
+ *
27
+ * @param {Uint8Array} message - The message to sign
28
+ * @returns {Promise<ByteArray>} The signature of the message
29
+ */
9
30
  signMessage(message: Uint8Array): Promise<ByteArray>;
31
+ createTransfer(instructions: TransactionInstruction[], connection: Connection, version?: "versioned"): Promise<VersionedTransaction>;
32
+ createTransfer(instructions: TransactionInstruction[], connection: Connection, version?: "legacy"): Promise<Transaction>;
33
+ createTransfer(instructions: TransactionInstruction[], connection: Connection): Promise<VersionedTransaction>;
34
+ /**
35
+ * Adds sponsorship to a transaction. Used to have a party like Alchemy pay for the transaction.
36
+ *
37
+ * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction
38
+ * @param {Connection} connection - The connection to use for the transaction
39
+ * @param {string} [policyId] - The policy ID to add sponsorship to
40
+ * @returns {Promise<VersionedTransaction>} The transaction with sponsorship added
41
+ */
42
+ addSponsorship(instructions: TransactionInstruction[], connection: Connection, policyId: string): Promise<VersionedTransaction>;
10
43
  private formatSignatureForSolana;
11
44
  private getMessageToSign;
12
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"solanaSigner.d.ts","sourceRoot":"","sources":["../../src/solanaSigner.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,KAAK,oBAAoB,EAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA+B,KAAK,SAAS,EAAY,MAAM,MAAM,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAItD,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAAmB;IACjC,OAAO,EAAE,MAAM,CAAC;gBAEX,MAAM,EAAE,gBAAgB;IAQ9B,YAAY,CAChB,EAAE,EAAE,WAAW,GAAG,oBAAoB,GACrC,OAAO,CAAC,WAAW,GAAG,oBAAoB,CAAC;IAwBxC,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAmB1D,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,gBAAgB;CASzB"}
1
+ {"version":3,"file":"solanaSigner.d.ts","sourceRoot":"","sources":["../../src/solanaSigner.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAEV,WAAW,EACX,sBAAsB,EAEtB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAA+B,KAAK,SAAS,EAAY,MAAM,MAAM,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD;;;GAGG;AACH,qBAAa,YAAY;IACvB,QAAQ,CAAC,aAAa,EAAE,gBAAgB,CAAC;IACzC,SAAgB,OAAO,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;gBACS,MAAM,EAAE,gBAAgB;IAQpC;;;;;OAKG;IACG,YAAY,CAChB,WAAW,EAAE,WAAW,GAAG,oBAAoB,GAC9C,OAAO,CAAC,WAAW,GAAG,oBAAoB,CAAC;IAwB9C;;;;;OAKG;IACG,WAAW,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;IAmBpD,cAAc,CAClB,YAAY,EAAE,sBAAsB,EAAE,EACtC,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,oBAAoB,CAAC;IAC1B,cAAc,CAClB,YAAY,EAAE,sBAAsB,EAAE,EACtC,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IACjB,cAAc,CAClB,YAAY,EAAE,sBAAsB,EAAE,EACtC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,oBAAoB,CAAC;IA6ChC;;;;;;;OAOG;IACG,cAAc,CAClB,YAAY,EAAE,sBAAsB,EAAE,EACtC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,CAAC;IAmDhC,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,gBAAgB;CASzB"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "4.25.1";
1
+ export declare const VERSION = "4.27.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@account-kit/signer",
3
- "version": "4.25.1",
3
+ "version": "4.27.0",
4
4
  "description": "Core interfaces and clients for interfacing with the Alchemy Signer API",
5
5
  "author": "Alchemy",
6
6
  "license": "MIT",
@@ -42,6 +42,7 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@tanstack/react-query": "^5.28.9",
45
+ "@types/bs58": "^4.0.4",
45
46
  "react": "^18.2.0",
46
47
  "react-dom": "^18.2.0",
47
48
  "tailwindcss": "^3.4.3",
@@ -50,13 +51,14 @@
50
51
  "vitest": "^2.0.4"
51
52
  },
52
53
  "dependencies": {
53
- "@aa-sdk/core": "^4.25.1",
54
- "@account-kit/logging": "^4.25.1",
54
+ "@aa-sdk/core": "^4.27.0",
55
+ "@account-kit/logging": "^4.27.0",
55
56
  "@solana/web3.js": "^1.98.0",
56
57
  "@turnkey/http": "^2.6.2",
57
58
  "@turnkey/iframe-stamper": "^1.0.0",
58
59
  "@turnkey/viem": "^0.4.8",
59
60
  "@turnkey/webauthn-stamper": "^0.4.3",
61
+ "bs58": "^6.0.0",
60
62
  "jwt-decode": "^4.0.0",
61
63
  "zod": "^3.22.4",
62
64
  "zustand": "^5.0.0-rc.2"
@@ -76,5 +78,5 @@
76
78
  "url": "https://github.com/alchemyplatform/aa-sdk/issues"
77
79
  },
78
80
  "homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
79
- "gitHead": "a9fea72b02f77909ca0dfc9cdecda7af6de0b17d"
81
+ "gitHead": "19b59caa4fcb4e057f8e84a81f77843650fcab25"
80
82
  }
package/src/index.ts CHANGED
@@ -20,3 +20,4 @@ export { AlchemyWebSigner } from "./signer.js";
20
20
  export type * from "./solanaSigner.js";
21
21
  export type * from "./types.js";
22
22
  export { AlchemySignerStatus } from "./types.js";
23
+ export { SolanaSigner } from "./solanaSigner.js";
@@ -1,17 +1,28 @@
1
1
  import {
2
+ Connection,
2
3
  PublicKey,
3
4
  Transaction,
4
- type VersionedTransaction,
5
+ TransactionInstruction,
6
+ TransactionMessage,
7
+ VersionedTransaction,
5
8
  } from "@solana/web3.js";
6
9
  import { size, slice, toBytes, toHex, type ByteArray, type Hex } from "viem";
7
10
  import type { BaseSignerClient } from "./client/base";
8
11
  import { NotAuthenticatedError } from "./errors.js";
9
12
 
10
- // TODO: I don't want this to be a class so that the flow is closer to how we do this for `toViemAccount`
13
+ /**
14
+ * The SolanaSigner class is used to sign transactions and messages for the Solana blockchain.
15
+ * It provides methods to add signatures to transactions and sign messages.
16
+ */
11
17
  export class SolanaSigner {
12
- private alchemyClient: BaseSignerClient;
13
- public address: string;
18
+ readonly alchemyClient: BaseSignerClient;
19
+ public readonly address: string;
14
20
 
21
+ /**
22
+ * Constructor for the SolanaSigner class which is a wrapper around the alchemy client, and is more focused on the solana web3
23
+ *
24
+ * @param {object} client This is the client that will be used to sign the transaction, and we are just having functions on top of it.
25
+ */
15
26
  constructor(client: BaseSignerClient) {
16
27
  this.alchemyClient = client;
17
28
  if (!client.getUser()) throw new Error("Must be authenticated!");
@@ -20,8 +31,14 @@ export class SolanaSigner {
20
31
  this.address = client.getUser()!.solanaAddress!;
21
32
  }
22
33
 
34
+ /**
35
+ * Adds a signature of the client user to a transaction
36
+ *
37
+ * @param {Transaction | VersionedTransaction} transaction - The transaction to add the signature to
38
+ * @returns {Promise<Transaction | VersionedTransaction >} The transaction with the signature added
39
+ */
23
40
  async addSignature(
24
- tx: Transaction | VersionedTransaction
41
+ transaction: Transaction | VersionedTransaction
25
42
  ): Promise<Transaction | VersionedTransaction> {
26
43
  const user = this.alchemyClient.getUser();
27
44
  if (!user) {
@@ -33,19 +50,25 @@ export class SolanaSigner {
33
50
  }
34
51
 
35
52
  const fromKey = new PublicKey(user.solanaAddress);
36
- const messageToSign = this.getMessageToSign(tx);
53
+ const messageToSign = this.getMessageToSign(transaction);
37
54
  const signature = await this.alchemyClient.signRawMessage(
38
55
  messageToSign,
39
56
  "SOLANA"
40
57
  );
41
58
 
42
- tx.addSignature(
59
+ transaction.addSignature(
43
60
  fromKey,
44
61
  Buffer.from(toBytes(this.formatSignatureForSolana(signature)))
45
62
  );
46
- return tx;
63
+ return transaction;
47
64
  }
48
65
 
66
+ /**
67
+ * Signs a message
68
+ *
69
+ * @param {Uint8Array} message - The message to sign
70
+ * @returns {Promise<ByteArray>} The signature of the message
71
+ */
49
72
  async signMessage(message: Uint8Array): Promise<ByteArray> {
50
73
  const user = this.alchemyClient.getUser();
51
74
  if (!user) {
@@ -65,6 +88,127 @@ export class SolanaSigner {
65
88
  return toBytes(this.formatSignatureForSolana(signature));
66
89
  }
67
90
 
91
+ async createTransfer(
92
+ instructions: TransactionInstruction[],
93
+ connection: Connection,
94
+ version?: "versioned"
95
+ ): Promise<VersionedTransaction>;
96
+ async createTransfer(
97
+ instructions: TransactionInstruction[],
98
+ connection: Connection,
99
+ version?: "legacy"
100
+ ): Promise<Transaction>;
101
+ async createTransfer(
102
+ instructions: TransactionInstruction[],
103
+ connection: Connection
104
+ ): Promise<VersionedTransaction>;
105
+
106
+ /**
107
+ * Creates a transfer transaction. Used for the SolanaCard example.
108
+ *
109
+ * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction
110
+ * @param {Connection} connection - The connection to use for the transaction
111
+ * @param {"versioned" | "legacy"} [version] - The version of the transaction
112
+ * @returns {Promise<Transaction | VersionedTransaction>} The transfer transaction
113
+ */
114
+ async createTransfer(
115
+ instructions: TransactionInstruction[],
116
+ connection: Connection,
117
+ version?: string
118
+ ): Promise<Transaction | VersionedTransaction> {
119
+ const blockhash = (await connection.getLatestBlockhash()).blockhash;
120
+
121
+ let transferTransaction;
122
+
123
+ if (version === "legacy") {
124
+ // Legacy transaction
125
+ transferTransaction = instructions.reduce(
126
+ (tx, instruction) => tx.add(instruction),
127
+ new Transaction()
128
+ );
129
+
130
+ // Get a recent block hash
131
+ transferTransaction.recentBlockhash = blockhash;
132
+ // Set the signer
133
+ transferTransaction.feePayer = new PublicKey(this.address);
134
+ } else {
135
+ // VersionedTransaction
136
+ const txMessage = new TransactionMessage({
137
+ payerKey: new PublicKey(this.address),
138
+ recentBlockhash: blockhash,
139
+ instructions,
140
+ });
141
+
142
+ const versionedTxMessage = txMessage.compileToV0Message();
143
+ transferTransaction = new VersionedTransaction(versionedTxMessage);
144
+ }
145
+
146
+ return transferTransaction;
147
+ }
148
+
149
+ /**
150
+ * Adds sponsorship to a transaction. Used to have a party like Alchemy pay for the transaction.
151
+ *
152
+ * @param {TransactionInstruction[]} instructions - The instructions to add to the transaction
153
+ * @param {Connection} connection - The connection to use for the transaction
154
+ * @param {string} [policyId] - The policy ID to add sponsorship to
155
+ * @returns {Promise<VersionedTransaction>} The transaction with sponsorship added
156
+ */
157
+ async addSponsorship(
158
+ instructions: TransactionInstruction[],
159
+ connection: Connection,
160
+ policyId: string
161
+ ): Promise<VersionedTransaction> {
162
+ const { blockhash } = await connection.getLatestBlockhash({
163
+ commitment: "finalized",
164
+ });
165
+ const message = new TransactionMessage({
166
+ // Right now the backend will rewrite this payer Key to the server's address
167
+ payerKey: new PublicKey(this.address),
168
+ recentBlockhash: blockhash,
169
+ instructions,
170
+ }).compileToV0Message();
171
+ const versionedTransaction = new VersionedTransaction(message);
172
+ const serializedTransaction = Buffer.from(
173
+ versionedTransaction.serialize()
174
+ ).toString("base64");
175
+ const body = JSON.stringify({
176
+ id: crypto?.randomUUID() ?? Math.floor(Math.random() * 1000000),
177
+ jsonrpc: "2.0",
178
+ method: "alchemy_requestFeePayer",
179
+ params: [
180
+ {
181
+ policyId,
182
+ serializedTransaction,
183
+ },
184
+ ],
185
+ });
186
+ const options = {
187
+ method: "POST",
188
+ headers: {
189
+ accept: "application/json",
190
+ "content-type": "application/json",
191
+ },
192
+ body,
193
+ };
194
+
195
+ const response = await fetch(
196
+ // TODO: Use the connection??
197
+ connection.rpcEndpoint,
198
+ options
199
+ );
200
+ const jsonResponse = await response.json();
201
+ if (!jsonResponse?.result?.serializedTransaction)
202
+ throw new Error(
203
+ `Response doesn't include the serializedTransaction ${JSON.stringify(
204
+ jsonResponse
205
+ )}`
206
+ );
207
+ return VersionedTransaction.deserialize(
208
+ decodeBase64(jsonResponse.result.serializedTransaction)
209
+ );
210
+ }
211
+
68
212
  private formatSignatureForSolana(signature: Hex): Hex {
69
213
  if (size(signature) === 64) return signature;
70
214
 
@@ -81,3 +225,6 @@ export class SolanaSigner {
81
225
  return toHex(messageToSign);
82
226
  }
83
227
  }
228
+ function decodeBase64(serializedTransaction: string): Uint8Array {
229
+ return Buffer.from(serializedTransaction, "base64");
230
+ }
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.25.1";
3
+ export const VERSION = "4.27.0";