@alchemy/wallet-apis 5.0.0-beta.3 → 5.0.0-beta.31
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/README.md +3 -1
- package/dist/esm/actions/prepareCalls.d.ts +8 -3
- package/dist/esm/actions/prepareCalls.js +8 -0
- package/dist/esm/actions/prepareCalls.js.map +1 -1
- package/dist/esm/actions/requestAccount.d.ts +4 -3
- package/dist/esm/actions/requestAccount.js.map +1 -1
- package/dist/esm/actions/sendCalls.d.ts +5 -2
- package/dist/esm/actions/sendCalls.js +5 -2
- package/dist/esm/actions/sendCalls.js.map +1 -1
- package/dist/esm/actions/sendPreparedCalls.d.ts +3 -1
- package/dist/esm/actions/sendPreparedCalls.js.map +1 -1
- package/dist/esm/actions/signPreparedCalls.d.ts +2 -0
- package/dist/esm/actions/signPreparedCalls.js +14 -1
- package/dist/esm/actions/signPreparedCalls.js.map +1 -1
- package/dist/esm/actions/signSignatureRequest.d.ts +4 -4
- package/dist/esm/actions/signSignatureRequest.js +1 -1
- package/dist/esm/actions/signSignatureRequest.js.map +1 -1
- package/dist/esm/actions/signTypedData.d.ts +14 -4
- package/dist/esm/actions/signTypedData.js.map +1 -1
- package/dist/esm/actions/solana/getCallsStatus.d.ts +24 -0
- package/dist/esm/actions/solana/getCallsStatus.js +44 -0
- package/dist/esm/actions/solana/getCallsStatus.js.map +1 -0
- package/dist/esm/actions/solana/prepareCalls.d.ts +46 -0
- package/dist/esm/actions/solana/prepareCalls.js +70 -0
- package/dist/esm/actions/solana/prepareCalls.js.map +1 -0
- package/dist/esm/actions/solana/sendCalls.d.ts +34 -0
- package/dist/esm/actions/solana/sendCalls.js +44 -0
- package/dist/esm/actions/solana/sendCalls.js.map +1 -0
- package/dist/esm/actions/solana/sendPreparedCalls.d.ts +24 -0
- package/dist/esm/actions/solana/sendPreparedCalls.js +32 -0
- package/dist/esm/actions/solana/sendPreparedCalls.js.map +1 -0
- package/dist/esm/actions/solana/signPreparedCalls.d.ts +23 -0
- package/dist/esm/actions/solana/signPreparedCalls.js +24 -0
- package/dist/esm/actions/solana/signPreparedCalls.js.map +1 -0
- package/dist/esm/actions/solana/signSignatureRequest.d.ts +10 -0
- package/dist/esm/actions/solana/signSignatureRequest.js +33 -0
- package/dist/esm/actions/solana/signSignatureRequest.js.map +1 -0
- package/dist/esm/actions/solana/waitForCallsStatus.d.ts +24 -0
- package/dist/esm/actions/solana/waitForCallsStatus.js +46 -0
- package/dist/esm/actions/solana/waitForCallsStatus.js.map +1 -0
- package/dist/esm/actions/undelegateAccount.d.ts +37 -0
- package/dist/esm/actions/undelegateAccount.js +49 -0
- package/dist/esm/actions/undelegateAccount.js.map +1 -0
- package/dist/esm/adapters/SolanaSignerError.d.ts +4 -0
- package/dist/esm/adapters/SolanaSignerError.js +13 -0
- package/dist/esm/adapters/SolanaSignerError.js.map +1 -0
- package/dist/esm/adapters/fromKeypair.d.ts +21 -0
- package/dist/esm/adapters/fromKeypair.js +46 -0
- package/dist/esm/adapters/fromKeypair.js.map +1 -0
- package/dist/esm/adapters/fromKitSigner.d.ts +21 -0
- package/dist/esm/adapters/fromKitSigner.js +61 -0
- package/dist/esm/adapters/fromKitSigner.js.map +1 -0
- package/dist/esm/adapters/fromWalletAdapter.d.ts +26 -0
- package/dist/esm/adapters/fromWalletAdapter.js +45 -0
- package/dist/esm/adapters/fromWalletAdapter.js.map +1 -0
- package/dist/esm/adapters/fromWalletStandard.d.ts +31 -0
- package/dist/esm/adapters/fromWalletStandard.js +53 -0
- package/dist/esm/adapters/fromWalletStandard.js.map +1 -0
- package/dist/esm/adapters/resolveSignerSlot.d.ts +10 -0
- package/dist/esm/adapters/resolveSignerSlot.js +39 -0
- package/dist/esm/adapters/resolveSignerSlot.js.map +1 -0
- package/dist/esm/client.d.ts +29 -14
- package/dist/esm/client.js +63 -19
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/decorators/smartWalletActions.d.ts +2 -0
- package/dist/esm/decorators/smartWalletActions.js +4 -2
- package/dist/esm/decorators/smartWalletActions.js.map +1 -1
- package/dist/esm/decorators/solanaSmartWalletActions.d.ts +16 -0
- package/dist/esm/decorators/solanaSmartWalletActions.js +16 -0
- package/dist/esm/decorators/solanaSmartWalletActions.js.map +1 -0
- package/dist/esm/experimental/actions/requestQuoteV0.d.ts +48 -11
- package/dist/esm/experimental/actions/requestQuoteV0.js +8 -4
- package/dist/esm/experimental/actions/requestQuoteV0.js.map +1 -1
- package/dist/esm/experimental/swapActionsDecorator.d.ts +3 -0
- package/dist/esm/experimental/swapActionsDecorator.js.map +1 -1
- package/dist/esm/exports/index.d.ts +5 -3
- package/dist/esm/exports/index.js +1 -0
- package/dist/esm/exports/index.js.map +1 -1
- package/dist/esm/exports/solana.d.ts +24 -0
- package/dist/esm/exports/solana.js +15 -0
- package/dist/esm/exports/solana.js.map +1 -0
- package/dist/esm/types.d.ts +28 -4
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/utils/assertions.d.ts +4 -2
- package/dist/esm/utils/assertions.js +6 -0
- package/dist/esm/utils/assertions.js.map +1 -1
- package/dist/esm/utils/capabilities.d.ts +22 -6
- package/dist/esm/utils/capabilities.js +19 -2
- package/dist/esm/utils/capabilities.js.map +1 -1
- package/dist/esm/utils/format.d.ts +2 -2
- package/dist/esm/utils/format.js +4 -3
- package/dist/esm/utils/format.js.map +1 -1
- package/dist/esm/utils/schema.d.ts +14 -14
- package/dist/esm/utils/schema.js +35 -39
- package/dist/esm/utils/schema.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/actions/prepareCalls.d.ts +8 -3
- package/dist/types/actions/prepareCalls.d.ts.map +1 -1
- package/dist/types/actions/requestAccount.d.ts +4 -3
- package/dist/types/actions/requestAccount.d.ts.map +1 -1
- package/dist/types/actions/sendCalls.d.ts +5 -2
- package/dist/types/actions/sendCalls.d.ts.map +1 -1
- package/dist/types/actions/sendPreparedCalls.d.ts +3 -1
- package/dist/types/actions/sendPreparedCalls.d.ts.map +1 -1
- package/dist/types/actions/signPreparedCalls.d.ts +2 -0
- package/dist/types/actions/signPreparedCalls.d.ts.map +1 -1
- package/dist/types/actions/signSignatureRequest.d.ts +4 -4
- package/dist/types/actions/signSignatureRequest.d.ts.map +1 -1
- package/dist/types/actions/signTypedData.d.ts +14 -4
- package/dist/types/actions/signTypedData.d.ts.map +1 -1
- package/dist/types/actions/solana/getCallsStatus.d.ts +25 -0
- package/dist/types/actions/solana/getCallsStatus.d.ts.map +1 -0
- package/dist/types/actions/solana/prepareCalls.d.ts +47 -0
- package/dist/types/actions/solana/prepareCalls.d.ts.map +1 -0
- package/dist/types/actions/solana/sendCalls.d.ts +35 -0
- package/dist/types/actions/solana/sendCalls.d.ts.map +1 -0
- package/dist/types/actions/solana/sendPreparedCalls.d.ts +25 -0
- package/dist/types/actions/solana/sendPreparedCalls.d.ts.map +1 -0
- package/dist/types/actions/solana/signPreparedCalls.d.ts +24 -0
- package/dist/types/actions/solana/signPreparedCalls.d.ts.map +1 -0
- package/dist/types/actions/solana/signSignatureRequest.d.ts +11 -0
- package/dist/types/actions/solana/signSignatureRequest.d.ts.map +1 -0
- package/dist/types/actions/solana/waitForCallsStatus.d.ts +25 -0
- package/dist/types/actions/solana/waitForCallsStatus.d.ts.map +1 -0
- package/dist/types/actions/undelegateAccount.d.ts +38 -0
- package/dist/types/actions/undelegateAccount.d.ts.map +1 -0
- package/dist/types/adapters/SolanaSignerError.d.ts +5 -0
- package/dist/types/adapters/SolanaSignerError.d.ts.map +1 -0
- package/dist/types/adapters/fromKeypair.d.ts +22 -0
- package/dist/types/adapters/fromKeypair.d.ts.map +1 -0
- package/dist/types/adapters/fromKitSigner.d.ts +22 -0
- package/dist/types/adapters/fromKitSigner.d.ts.map +1 -0
- package/dist/types/adapters/fromWalletAdapter.d.ts +27 -0
- package/dist/types/adapters/fromWalletAdapter.d.ts.map +1 -0
- package/dist/types/adapters/fromWalletStandard.d.ts +32 -0
- package/dist/types/adapters/fromWalletStandard.d.ts.map +1 -0
- package/dist/types/adapters/resolveSignerSlot.d.ts +11 -0
- package/dist/types/adapters/resolveSignerSlot.d.ts.map +1 -0
- package/dist/types/client.d.ts +29 -14
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/decorators/smartWalletActions.d.ts +2 -0
- package/dist/types/decorators/smartWalletActions.d.ts.map +1 -1
- package/dist/types/decorators/solanaSmartWalletActions.d.ts +17 -0
- package/dist/types/decorators/solanaSmartWalletActions.d.ts.map +1 -0
- package/dist/types/experimental/actions/requestQuoteV0.d.ts +48 -11
- package/dist/types/experimental/actions/requestQuoteV0.d.ts.map +1 -1
- package/dist/types/experimental/swapActionsDecorator.d.ts +3 -0
- package/dist/types/experimental/swapActionsDecorator.d.ts.map +1 -1
- package/dist/types/exports/index.d.ts +5 -3
- package/dist/types/exports/index.d.ts.map +1 -1
- package/dist/types/exports/solana.d.ts +25 -0
- package/dist/types/exports/solana.d.ts.map +1 -0
- package/dist/types/types.d.ts +28 -4
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/assertions.d.ts +4 -2
- package/dist/types/utils/assertions.d.ts.map +1 -1
- package/dist/types/utils/capabilities.d.ts +22 -6
- package/dist/types/utils/capabilities.d.ts.map +1 -1
- package/dist/types/utils/format.d.ts +2 -2
- package/dist/types/utils/format.d.ts.map +1 -1
- package/dist/types/utils/schema.d.ts +14 -14
- package/dist/types/utils/schema.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +29 -11
- package/src/actions/prepareCalls.ts +21 -3
- package/src/actions/requestAccount.ts +7 -5
- package/src/actions/sendCalls.ts +5 -2
- package/src/actions/sendPreparedCalls.ts +4 -1
- package/src/actions/signPreparedCalls.ts +15 -2
- package/src/actions/signSignatureRequest.ts +8 -8
- package/src/actions/signTypedData.ts +15 -7
- package/src/actions/solana/getCallsStatus.ts +79 -0
- package/src/actions/solana/prepareCalls.ts +120 -0
- package/src/actions/solana/sendCalls.ts +66 -0
- package/src/actions/solana/sendPreparedCalls.ts +65 -0
- package/src/actions/solana/signPreparedCalls.ts +50 -0
- package/src/actions/solana/signSignatureRequest.ts +63 -0
- package/src/actions/solana/waitForCallsStatus.ts +84 -0
- package/src/actions/undelegateAccount.ts +68 -0
- package/src/adapters/SolanaSignerError.ts +5 -0
- package/src/adapters/fromKeypair.ts +58 -0
- package/src/adapters/fromKitSigner.ts +82 -0
- package/src/adapters/fromWalletAdapter.ts +58 -0
- package/src/adapters/fromWalletStandard.ts +100 -0
- package/src/adapters/resolveSignerSlot.ts +46 -0
- package/src/client.ts +131 -18
- package/src/decorators/smartWalletActions.ts +11 -2
- package/src/decorators/solanaSmartWalletActions.ts +62 -0
- package/src/experimental/actions/requestQuoteV0.ts +40 -15
- package/src/experimental/swapActionsDecorator.ts +3 -0
- package/src/exports/index.ts +10 -4
- package/src/exports/solana.ts +36 -0
- package/src/types.ts +38 -7
- package/src/utils/assertions.ts +17 -2
- package/src/utils/capabilities.ts +40 -8
- package/src/utils/format.ts +8 -3
- package/src/utils/schema.ts +58 -69
- package/src/version.ts +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Prettify } from "viem";
|
|
2
|
+
import type {
|
|
3
|
+
DistributiveOmit,
|
|
4
|
+
InnerSolanaWalletApiClient,
|
|
5
|
+
} from "../../types.js";
|
|
6
|
+
import { isSolanaChain } from "../../utils/assertions.js";
|
|
7
|
+
import type { SolanaChainId } from "@alchemy/wallet-api-types";
|
|
8
|
+
import { SolanaPrepareCallsParams as SolanaPrepareCallsSchema } from "@alchemy/wallet-api-types";
|
|
9
|
+
import { wallet_prepareCalls as MethodSchema } from "@alchemy/wallet-api-types/rpc";
|
|
10
|
+
import type { z } from "zod";
|
|
11
|
+
import { BaseError } from "@alchemy/common";
|
|
12
|
+
import { LOGGER } from "../../logger.js";
|
|
13
|
+
import {
|
|
14
|
+
mergeSolanaClientCapabilities,
|
|
15
|
+
type WithCapabilities,
|
|
16
|
+
} from "../../utils/capabilities.js";
|
|
17
|
+
import {
|
|
18
|
+
methodSchema,
|
|
19
|
+
encode,
|
|
20
|
+
decode,
|
|
21
|
+
type MethodResponse,
|
|
22
|
+
} from "../../utils/schema.js";
|
|
23
|
+
|
|
24
|
+
const schema = methodSchema(MethodSchema);
|
|
25
|
+
type PrepareCallsResponse = MethodResponse<typeof MethodSchema>;
|
|
26
|
+
|
|
27
|
+
type BaseSolanaPrepareCallsParams = z.output<typeof SolanaPrepareCallsSchema>;
|
|
28
|
+
|
|
29
|
+
export type SolanaPrepareCallsParams = Prettify<
|
|
30
|
+
WithCapabilities<
|
|
31
|
+
DistributiveOmit<BaseSolanaPrepareCallsParams, "from" | "chainId"> & {
|
|
32
|
+
account?: string;
|
|
33
|
+
chainId?: SolanaChainId;
|
|
34
|
+
}
|
|
35
|
+
>
|
|
36
|
+
>;
|
|
37
|
+
|
|
38
|
+
type SolanaPrepareCallsResponse = Extract<
|
|
39
|
+
PrepareCallsResponse,
|
|
40
|
+
{ type: "solana-transaction-v0" }
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
function isSolanaResponse(
|
|
44
|
+
response: PrepareCallsResponse,
|
|
45
|
+
): response is SolanaPrepareCallsResponse {
|
|
46
|
+
return response.type === "solana-transaction-v0";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type SolanaPrepareCallsResult = SolanaPrepareCallsResponse;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Prepares Solana instructions for execution by building a versioned transaction.
|
|
53
|
+
* Returns the compiled transaction and a signature request that needs to be signed
|
|
54
|
+
* before submitting to sendPreparedCalls.
|
|
55
|
+
*
|
|
56
|
+
* @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
|
|
57
|
+
* @param {SolanaPrepareCallsParams} params - Parameters for preparing Solana calls
|
|
58
|
+
* @param {Array<{programId: string, accounts?: Array, data: Hex}>} params.calls - Array of Solana instructions
|
|
59
|
+
* @param {string} [params.account] - The Solana address to execute from. Defaults to the signer's address.
|
|
60
|
+
* @param {SolanaChainId} [params.chainId] - The Solana chain ID. Defaults to the client's chain.
|
|
61
|
+
* @param {object} [params.capabilities] - Optional capabilities (e.g. paymaster sponsorship)
|
|
62
|
+
* @returns {Promise<SolanaPrepareCallsResult>} The prepared Solana transaction with signature request
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const result = await client.prepareCalls({
|
|
67
|
+
* calls: [{
|
|
68
|
+
* programId: "11111111111111111111111111111111",
|
|
69
|
+
* data: "0x...",
|
|
70
|
+
* }],
|
|
71
|
+
* capabilities: {
|
|
72
|
+
* paymaster: { policyId: "your-policy-id" }
|
|
73
|
+
* }
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export async function prepareCalls(
|
|
78
|
+
client: InnerSolanaWalletApiClient,
|
|
79
|
+
params: SolanaPrepareCallsParams,
|
|
80
|
+
): Promise<SolanaPrepareCallsResult> {
|
|
81
|
+
const { account, chainId, capabilities: caps, ...rest } = params;
|
|
82
|
+
const from = account ?? client.solanaAccount;
|
|
83
|
+
if (!isSolanaChain(client.chain)) {
|
|
84
|
+
throw new BaseError("Expected a Solana chain on the client");
|
|
85
|
+
}
|
|
86
|
+
const resolvedChainId = chainId ?? client.chain.solanaChainId;
|
|
87
|
+
|
|
88
|
+
const merged = mergeSolanaClientCapabilities(client, caps);
|
|
89
|
+
const capabilities = merged?.paymaster
|
|
90
|
+
? { paymasterService: merged.paymaster }
|
|
91
|
+
: undefined;
|
|
92
|
+
|
|
93
|
+
LOGGER.debug("solana:prepareCalls:start", {
|
|
94
|
+
callsCount: params.calls?.length,
|
|
95
|
+
hasCapabilities: !!caps,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const rpcParams = encode(SolanaPrepareCallsSchema, {
|
|
99
|
+
...rest,
|
|
100
|
+
chainId: resolvedChainId,
|
|
101
|
+
from,
|
|
102
|
+
capabilities,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const rpcResp = await client.request({
|
|
106
|
+
method: "wallet_prepareCalls",
|
|
107
|
+
params: [rpcParams],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
LOGGER.debug("solana:prepareCalls:done");
|
|
111
|
+
const decoded = decode(schema.response, rpcResp);
|
|
112
|
+
|
|
113
|
+
if (!isSolanaResponse(decoded)) {
|
|
114
|
+
throw new BaseError(
|
|
115
|
+
`Unexpected EVM response from Solana prepareCalls: ${decoded.type}`,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return decoded;
|
|
120
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Prettify } from "viem";
|
|
2
|
+
import type {
|
|
3
|
+
DistributiveOmit,
|
|
4
|
+
InnerSolanaWalletApiClient,
|
|
5
|
+
} from "../../types.js";
|
|
6
|
+
import type { SolanaChainId } from "@alchemy/wallet-api-types";
|
|
7
|
+
import { prepareCalls, type SolanaPrepareCallsParams } from "./prepareCalls.js";
|
|
8
|
+
import { signPreparedCalls } from "./signPreparedCalls.js";
|
|
9
|
+
import {
|
|
10
|
+
sendPreparedCalls,
|
|
11
|
+
type SolanaSendPreparedCallsResult,
|
|
12
|
+
} from "./sendPreparedCalls.js";
|
|
13
|
+
import { LOGGER } from "../../logger.js";
|
|
14
|
+
|
|
15
|
+
export type SolanaSendCallsParams = Prettify<
|
|
16
|
+
DistributiveOmit<SolanaPrepareCallsParams, "chainId"> & {
|
|
17
|
+
chainId?: SolanaChainId;
|
|
18
|
+
}
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
export type SolanaSendCallsResult = Prettify<SolanaSendPreparedCallsResult>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Prepares, signs, and submits Solana instructions in a single call.
|
|
25
|
+
* Internally calls `prepareCalls`, `signPreparedCalls`, and `sendPreparedCalls`.
|
|
26
|
+
*
|
|
27
|
+
* @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
|
|
28
|
+
* @param {SolanaSendCallsParams} params - Parameters for sending Solana calls
|
|
29
|
+
* @param {Array<{programId: string, accounts?: Array, data: Hex}>} params.calls - Array of Solana instructions
|
|
30
|
+
* @param {string} [params.account] - The Solana address to execute from. Defaults to the signer's address.
|
|
31
|
+
* @param {object} [params.capabilities] - Optional capabilities (e.g. paymaster sponsorship)
|
|
32
|
+
* @returns {Promise<SolanaSendCallsResult>} The result containing the call ID
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const result = await client.sendCalls({
|
|
37
|
+
* calls: [{
|
|
38
|
+
* programId: "11111111111111111111111111111111",
|
|
39
|
+
* data: "0x...",
|
|
40
|
+
* }],
|
|
41
|
+
* capabilities: {
|
|
42
|
+
* paymaster: { policyId: "your-policy-id" }
|
|
43
|
+
* }
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export async function sendCalls(
|
|
48
|
+
client: InnerSolanaWalletApiClient,
|
|
49
|
+
params: SolanaSendCallsParams,
|
|
50
|
+
): Promise<SolanaSendCallsResult> {
|
|
51
|
+
LOGGER.info("solana:sendCalls:start", {
|
|
52
|
+
calls: params.calls?.length,
|
|
53
|
+
hasCapabilities: !!params.capabilities,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const { chainId, ...rest } = params;
|
|
57
|
+
const prepared = await prepareCalls(client, {
|
|
58
|
+
...rest,
|
|
59
|
+
...(chainId != null ? { chainId } : {}),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const signed = await signPreparedCalls(client, prepared);
|
|
63
|
+
const res = await sendPreparedCalls(client, signed);
|
|
64
|
+
LOGGER.info("solana:sendCalls:done");
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Prettify } from "viem";
|
|
2
|
+
import type { InnerSolanaWalletApiClient } from "../../types.js";
|
|
3
|
+
import { PreparedCall_SolanaV0_Signed as PreparedCall_SolanaV0_SignedSchema } from "@alchemy/wallet-api-types";
|
|
4
|
+
import type { z } from "zod";
|
|
5
|
+
import { BaseError } from "@alchemy/common";
|
|
6
|
+
import { LOGGER } from "../../logger.js";
|
|
7
|
+
import { wallet_sendPreparedCalls as MethodSchema } from "@alchemy/wallet-api-types/rpc";
|
|
8
|
+
import {
|
|
9
|
+
methodSchema,
|
|
10
|
+
encode,
|
|
11
|
+
decode,
|
|
12
|
+
type MethodResponse,
|
|
13
|
+
} from "../../utils/schema.js";
|
|
14
|
+
|
|
15
|
+
const schema = methodSchema(MethodSchema);
|
|
16
|
+
type SendPreparedCallsResponse = MethodResponse<typeof MethodSchema>;
|
|
17
|
+
|
|
18
|
+
export type SolanaSendPreparedCallsParams = Prettify<
|
|
19
|
+
z.output<typeof PreparedCall_SolanaV0_SignedSchema>
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
type SolanaSendPreparedCallsResponse = Extract<
|
|
23
|
+
SendPreparedCallsResponse,
|
|
24
|
+
{ details: { type: "solana-transaction-v0" } }
|
|
25
|
+
>;
|
|
26
|
+
|
|
27
|
+
export type SolanaSendPreparedCallsResult = SolanaSendPreparedCallsResponse;
|
|
28
|
+
|
|
29
|
+
function isSolanaResponse(
|
|
30
|
+
response: SendPreparedCallsResponse,
|
|
31
|
+
): response is SolanaSendPreparedCallsResult {
|
|
32
|
+
return response.details.type === "solana-transaction-v0";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Sends a signed Solana transaction.
|
|
37
|
+
* This method is used after signing the signature request returned from prepareCalls.
|
|
38
|
+
*
|
|
39
|
+
* @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
|
|
40
|
+
* @param {SolanaSendPreparedCallsParams} params - The signed Solana transaction
|
|
41
|
+
* @returns {Promise<SolanaSendPreparedCallsResult>} The result containing the call ID
|
|
42
|
+
*/
|
|
43
|
+
export async function sendPreparedCalls(
|
|
44
|
+
client: InnerSolanaWalletApiClient,
|
|
45
|
+
params: SolanaSendPreparedCallsParams,
|
|
46
|
+
): Promise<SolanaSendPreparedCallsResult> {
|
|
47
|
+
LOGGER.debug("solana:sendPreparedCalls:start", { type: params.type });
|
|
48
|
+
|
|
49
|
+
const rpcParams = encode(PreparedCall_SolanaV0_SignedSchema, params);
|
|
50
|
+
const rpcResp = await client.request({
|
|
51
|
+
method: "wallet_sendPreparedCalls",
|
|
52
|
+
params: [rpcParams],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
LOGGER.debug("solana:sendPreparedCalls:done");
|
|
56
|
+
const decoded = decode(schema.response, rpcResp);
|
|
57
|
+
|
|
58
|
+
if (!isSolanaResponse(decoded)) {
|
|
59
|
+
throw new BaseError(
|
|
60
|
+
`Unexpected EVM response from Solana sendPreparedCalls: ${decoded.details.type}`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return decoded;
|
|
65
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Prettify } from "viem";
|
|
2
|
+
import type { InnerSolanaWalletApiClient } from "../../types.js";
|
|
3
|
+
import {
|
|
4
|
+
signSolanaSignatureRequest,
|
|
5
|
+
type SolanaSignatureResult,
|
|
6
|
+
} from "./signSignatureRequest.js";
|
|
7
|
+
import type { SolanaPrepareCallsResult } from "./prepareCalls.js";
|
|
8
|
+
import { LOGGER } from "../../logger.js";
|
|
9
|
+
|
|
10
|
+
export type SolanaSignPreparedCallsParams = Prettify<SolanaPrepareCallsResult>;
|
|
11
|
+
|
|
12
|
+
export type SolanaSignPreparedCallsResult = Prettify<
|
|
13
|
+
Omit<
|
|
14
|
+
SolanaPrepareCallsResult,
|
|
15
|
+
"signatureRequest" | "feePayment" | "details"
|
|
16
|
+
> & {
|
|
17
|
+
signature: SolanaSignatureResult;
|
|
18
|
+
}
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Signs a prepared Solana transaction using the client's Ed25519 signer.
|
|
23
|
+
*
|
|
24
|
+
* @param {InnerSolanaWalletApiClient} client - The Solana wallet client
|
|
25
|
+
* @param {SolanaSignPreparedCallsParams} params - The prepared Solana transaction with signature request
|
|
26
|
+
* @returns {Promise<SolanaSignPreparedCallsResult>} The signed Solana transaction
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const prepared = await client.prepareCalls({ ... });
|
|
31
|
+
* const signed = await client.signPreparedCalls(prepared);
|
|
32
|
+
* const result = await client.sendPreparedCalls(signed);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export async function signPreparedCalls(
|
|
36
|
+
client: InnerSolanaWalletApiClient,
|
|
37
|
+
params: SolanaSignPreparedCallsParams,
|
|
38
|
+
): Promise<SolanaSignPreparedCallsResult> {
|
|
39
|
+
LOGGER.debug("solana:signPreparedCalls:start");
|
|
40
|
+
|
|
41
|
+
const signature = await signSolanaSignatureRequest(
|
|
42
|
+
client.owner,
|
|
43
|
+
params.signatureRequest,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const { signatureRequest: _, feePayment: __, details: ___, ...rest } = params;
|
|
47
|
+
|
|
48
|
+
LOGGER.debug("solana:signPreparedCalls:done");
|
|
49
|
+
return { ...rest, signature };
|
|
50
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { SolanaSigner } from "../../types.js";
|
|
2
|
+
import { LOGGER } from "../../logger.js";
|
|
3
|
+
import { hexToBytes } from "viem";
|
|
4
|
+
import { Base58 } from "ox";
|
|
5
|
+
import { findSignerSlot } from "../../adapters/resolveSignerSlot.js";
|
|
6
|
+
import { SolanaSignerError } from "../../adapters/SolanaSignerError.js";
|
|
7
|
+
|
|
8
|
+
export type SolanaSignatureRequestParams = {
|
|
9
|
+
type: "solana_signTransaction";
|
|
10
|
+
data: `0x${string}`;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type SolanaSignatureResult = {
|
|
14
|
+
type: "ed25519";
|
|
15
|
+
data: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export async function signSolanaSignatureRequest(
|
|
19
|
+
signer: SolanaSigner,
|
|
20
|
+
signatureRequest: SolanaSignatureRequestParams,
|
|
21
|
+
): Promise<SolanaSignatureResult> {
|
|
22
|
+
const txBytes = hexToBytes(signatureRequest.data);
|
|
23
|
+
|
|
24
|
+
const slotIndex = await findSignerSlot(txBytes, signer.address);
|
|
25
|
+
if (slotIndex < 0) {
|
|
26
|
+
throw new SolanaSignerError(
|
|
27
|
+
`Signer ${signer.address} is not a required signer in this transaction`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
LOGGER.debug("signSolanaSignatureRequest:signing");
|
|
32
|
+
|
|
33
|
+
const { signedTransaction } = await signer.signTransaction({
|
|
34
|
+
transaction: txBytes,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (signedTransaction[0] !== txBytes[0]) {
|
|
38
|
+
throw new SolanaSignerError(
|
|
39
|
+
`Signer returned a transaction with a different signature count (expected ${txBytes[0]}, got ${signedTransaction[0]})`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const offset = 1 + slotIndex * 64;
|
|
44
|
+
const rawSignature = signedTransaction.slice(offset, offset + 64);
|
|
45
|
+
|
|
46
|
+
if (rawSignature.length !== 64) {
|
|
47
|
+
throw new SolanaSignerError(
|
|
48
|
+
`Signed transaction too short to contain signature at slot ${slotIndex}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (rawSignature.every((b) => b === 0)) {
|
|
53
|
+
throw new SolanaSignerError(
|
|
54
|
+
`Signer ${signer.address} did not produce a signature at slot ${slotIndex}`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
LOGGER.debug("signSolanaSignatureRequest:ok");
|
|
59
|
+
return {
|
|
60
|
+
type: "ed25519",
|
|
61
|
+
data: Base58.fromBytes(rawSignature),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { InnerSolanaWalletApiClient } from "../../types.js";
|
|
2
|
+
import {
|
|
3
|
+
getCallsStatus,
|
|
4
|
+
type SolanaGetCallsStatusResult,
|
|
5
|
+
} from "./getCallsStatus.js";
|
|
6
|
+
import { BaseError } from "@alchemy/common";
|
|
7
|
+
import { LOGGER } from "../../logger.js";
|
|
8
|
+
|
|
9
|
+
export type SolanaWaitForCallsStatusParams = {
|
|
10
|
+
id: `0x${string}`;
|
|
11
|
+
pollingInterval?: number;
|
|
12
|
+
retryCount?: number;
|
|
13
|
+
retryDelay?: (opts: { count: number }) => number;
|
|
14
|
+
status?: (result: SolanaGetCallsStatusResult) => boolean;
|
|
15
|
+
throwOnFailure?: boolean;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type SolanaWaitForCallsStatusResult = SolanaGetCallsStatusResult;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Polls getCallsStatus until the call reaches a terminal state.
|
|
23
|
+
* Similar API to viem's waitForCallsStatus with retry, exponential backoff,
|
|
24
|
+
* configurable status predicate, throwOnFailure, and timeout.
|
|
25
|
+
*
|
|
26
|
+
* @param {InnerSolanaWalletApiClient} client - The Solana wallet API client
|
|
27
|
+
* @param {SolanaWaitForCallsStatusParams} params - The call ID and optional polling config
|
|
28
|
+
* @returns {Promise<SolanaWaitForCallsStatusResult>} The final status
|
|
29
|
+
*/
|
|
30
|
+
export async function waitForCallsStatus(
|
|
31
|
+
client: InnerSolanaWalletApiClient,
|
|
32
|
+
params: SolanaWaitForCallsStatusParams,
|
|
33
|
+
): Promise<SolanaWaitForCallsStatusResult> {
|
|
34
|
+
const {
|
|
35
|
+
id,
|
|
36
|
+
pollingInterval = client.pollingInterval,
|
|
37
|
+
retryCount = 4,
|
|
38
|
+
retryDelay = ({ count }: { count: number }) => ~~(1 << count) * 200,
|
|
39
|
+
status: isReady = ({ statusCode }) =>
|
|
40
|
+
statusCode === 200 || statusCode >= 300,
|
|
41
|
+
throwOnFailure = false,
|
|
42
|
+
timeout = 60_000,
|
|
43
|
+
} = params;
|
|
44
|
+
|
|
45
|
+
LOGGER.debug("solana:waitForCallsStatus:start", { id });
|
|
46
|
+
|
|
47
|
+
const start = Date.now();
|
|
48
|
+
|
|
49
|
+
while (Date.now() - start < timeout) {
|
|
50
|
+
let result: SolanaGetCallsStatusResult | undefined;
|
|
51
|
+
|
|
52
|
+
for (let attempt = 0; attempt <= retryCount; attempt++) {
|
|
53
|
+
try {
|
|
54
|
+
result = await getCallsStatus(client, { id });
|
|
55
|
+
break;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (attempt >= retryCount) throw error;
|
|
58
|
+
await new Promise((r) => setTimeout(r, retryDelay({ count: attempt })));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!result) throw new BaseError("Unexpected: no result after retries");
|
|
63
|
+
|
|
64
|
+
if (throwOnFailure && result.status === "failure") {
|
|
65
|
+
throw new BaseError(
|
|
66
|
+
`Solana call bundle failed with status code ${result.statusCode}`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (isReady(result)) {
|
|
71
|
+
LOGGER.debug("solana:waitForCallsStatus:done", {
|
|
72
|
+
status: result.status,
|
|
73
|
+
statusCode: result.statusCode,
|
|
74
|
+
});
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await new Promise((r) => setTimeout(r, pollingInterval));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new BaseError(
|
|
82
|
+
`Timed out while waiting for call bundle with id "${id}" to be confirmed.`,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { zeroAddress, type Chain, type Prettify } from "viem";
|
|
2
|
+
import type { InnerWalletApiClient } from "../types.js";
|
|
3
|
+
import { LOGGER } from "../logger.js";
|
|
4
|
+
import { resolveAddress, type AccountParam } from "../utils/resolve.js";
|
|
5
|
+
import { sendCalls, type SendCallsResult } from "./sendCalls.js";
|
|
6
|
+
|
|
7
|
+
export type UndelegateAccountParams = Prettify<{
|
|
8
|
+
account?: AccountParam;
|
|
9
|
+
chain?: Pick<Chain, "id">;
|
|
10
|
+
capabilities?: {
|
|
11
|
+
paymaster?: {
|
|
12
|
+
policyId: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
export type UndelegateAccountResult = Prettify<SendCallsResult>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Prepares, signs, and sends an EIP-7702 undelegation to remove delegation from an EOA.
|
|
21
|
+
* Gas is sponsored by Alchemy (requires Enterprise plan).
|
|
22
|
+
*
|
|
23
|
+
* A BSO (Bundler Sponsorship Override) policy ID must be provided either via
|
|
24
|
+
* `params.capabilities.paymaster.policyId` or pre-configured on the client via `policyIds`.
|
|
25
|
+
*
|
|
26
|
+
* @param {InnerWalletApiClient} client - The wallet API client to use for the request
|
|
27
|
+
* @param {UndelegateAccountParams} params - Parameters for undelegating the account
|
|
28
|
+
* @param {AccountParam} [params.account] - The account to undelegate. Defaults to the client's account (signer address).
|
|
29
|
+
* @param {object} [params.chain] - The chain. Defaults to the client's chain.
|
|
30
|
+
* @param {object} [params.capabilities] - Optional capabilities. If omitted, falls back to the policy ID(s) set on the client.
|
|
31
|
+
* @param {object} [params.capabilities.paymaster] - Paymaster capabilities. Requires a BSO policy ID.
|
|
32
|
+
* @param {string} [params.capabilities.paymaster.policyId] - The BSO policy ID to use for gas sponsorship.
|
|
33
|
+
* @returns {Promise<UndelegateAccountResult>} A Promise that resolves to the result containing the call ID.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const result = await client.undelegateAccount();
|
|
38
|
+
* const status = await client.waitForCallsStatus({ id: result.id });
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export async function undelegateAccount(
|
|
42
|
+
client: InnerWalletApiClient,
|
|
43
|
+
params?: UndelegateAccountParams,
|
|
44
|
+
): Promise<UndelegateAccountResult> {
|
|
45
|
+
const account = params?.account
|
|
46
|
+
? resolveAddress(params.account)
|
|
47
|
+
: client.account.address;
|
|
48
|
+
|
|
49
|
+
LOGGER.info("undelegateAccount:start", {
|
|
50
|
+
account,
|
|
51
|
+
chain: params?.chain,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const result = await sendCalls(client, {
|
|
55
|
+
calls: [],
|
|
56
|
+
account,
|
|
57
|
+
...(params?.chain != null ? { chain: params.chain } : {}),
|
|
58
|
+
capabilities: {
|
|
59
|
+
...params?.capabilities,
|
|
60
|
+
eip7702Auth: {
|
|
61
|
+
delegation: zeroAddress,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
LOGGER.info("undelegateAccount:done", { id: result.id });
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SolanaSigner } from "../types.js";
|
|
2
|
+
import { SolanaSignerError } from "./SolanaSignerError.js";
|
|
3
|
+
import { findSignerSlot } from "./resolveSignerSlot.js";
|
|
4
|
+
|
|
5
|
+
/** Raw Ed25519 keypair signer (e.g. `Keypair` from `@solana/web3.js` v1 or a bare Ed25519 key). */
|
|
6
|
+
export interface SolanaKeypairSigner {
|
|
7
|
+
address: string;
|
|
8
|
+
signMessage(message: Uint8Array): Promise<Uint8Array>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Adapts a raw Ed25519 keypair signer into a {@link SolanaSigner}.
|
|
13
|
+
*
|
|
14
|
+
* Use this for legacy `@solana/web3.js` v1 `Keypair` signers or any signer
|
|
15
|
+
* that exposes a `signMessage(bytes) => signature` interface. For
|
|
16
|
+
* `@solana/kit` signers, use {@link fromKitSigner}. For browser wallets
|
|
17
|
+
* (wallet adapter, Phantom, etc.), use {@link fromWalletAdapter}. For
|
|
18
|
+
* wallet-standard wallets, use {@link fromWalletStandard}.
|
|
19
|
+
*
|
|
20
|
+
* Requires `@solana/kit` or `@solana/web3.js` as a peer dependency.
|
|
21
|
+
*
|
|
22
|
+
* @param {SolanaKeypairSigner} signer - The raw Ed25519 keypair signer to adapt
|
|
23
|
+
* @returns {SolanaSigner} A SolanaSigner compatible with `createSmartWalletClient`
|
|
24
|
+
*/
|
|
25
|
+
export function fromKeypair(signer: SolanaKeypairSigner): SolanaSigner {
|
|
26
|
+
return {
|
|
27
|
+
address: signer.address,
|
|
28
|
+
async signTransaction({ transaction }) {
|
|
29
|
+
const numSigs = transaction[0];
|
|
30
|
+
const messageStart = 1 + numSigs * 64;
|
|
31
|
+
const messageBytes = transaction.slice(messageStart);
|
|
32
|
+
let sig: Uint8Array;
|
|
33
|
+
try {
|
|
34
|
+
sig = await signer.signMessage(messageBytes);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
throw new SolanaSignerError("Keypair signer failed to sign message", {
|
|
37
|
+
cause: e as Error,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (sig.length !== 64) {
|
|
41
|
+
throw new SolanaSignerError(
|
|
42
|
+
`Expected a 64-byte Ed25519 signature but received ${sig.length} bytes`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const slotIndex = await findSignerSlot(transaction, signer.address);
|
|
47
|
+
if (slotIndex < 0) {
|
|
48
|
+
throw new SolanaSignerError(
|
|
49
|
+
`Signer ${signer.address} is not a required signer in this transaction`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const signedTx = new Uint8Array(transaction);
|
|
54
|
+
signedTx.set(sig, 1 + slotIndex * 64);
|
|
55
|
+
return { signedTransaction: signedTx };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { SolanaSigner } from "../types.js";
|
|
2
|
+
import { SolanaSignerError } from "./SolanaSignerError.js";
|
|
3
|
+
import { findSignerSlot } from "./resolveSignerSlot.js";
|
|
4
|
+
|
|
5
|
+
/** Any {@link https://solanakit.com @solana/kit} signer that implements `signTransactions` (e.g. `TransactionPartialSigner`, `KeyPairSigner`). */
|
|
6
|
+
export interface SolanaTransactionPartialSigner {
|
|
7
|
+
address: string;
|
|
8
|
+
signTransactions(
|
|
9
|
+
transactions: readonly unknown[],
|
|
10
|
+
): Promise<readonly Record<string, Uint8Array>[]>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Adapts an {@link https://solanakit.com @solana/kit} signer into a {@link SolanaSigner}.
|
|
15
|
+
*
|
|
16
|
+
* Accepts any signer that implements `signTransactions`, including
|
|
17
|
+
* `KeyPairSigner`, `TransactionPartialSigner`, and `NoopSigner`. For raw
|
|
18
|
+
* Ed25519 keypairs, use {@link fromKeypair}. For browser wallets (wallet
|
|
19
|
+
* adapter, Phantom, etc.), use {@link fromWalletAdapter}. For
|
|
20
|
+
* wallet-standard wallets, use {@link fromWalletStandard}.
|
|
21
|
+
*
|
|
22
|
+
* Requires `@solana/kit` as a peer dependency.
|
|
23
|
+
*
|
|
24
|
+
* @param {SolanaTransactionPartialSigner} signer - The @solana/kit signer to adapt
|
|
25
|
+
* @returns {SolanaSigner} A SolanaSigner compatible with `createSmartWalletClient`
|
|
26
|
+
*/
|
|
27
|
+
export function fromKitSigner(
|
|
28
|
+
signer: SolanaTransactionPartialSigner,
|
|
29
|
+
): SolanaSigner {
|
|
30
|
+
return {
|
|
31
|
+
address: signer.address,
|
|
32
|
+
async signTransaction({ transaction }) {
|
|
33
|
+
let tx: unknown;
|
|
34
|
+
try {
|
|
35
|
+
const { getTransactionCodec } = await import("@solana/kit");
|
|
36
|
+
const codec = getTransactionCodec();
|
|
37
|
+
tx = codec.decode(transaction);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
throw new SolanaSignerError("Failed to decode transaction", {
|
|
40
|
+
cause: e as Error,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let sigDict: Record<string, Uint8Array> | undefined;
|
|
45
|
+
try {
|
|
46
|
+
[sigDict] = await signer.signTransactions([tx]);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
throw new SolanaSignerError("Kit signer failed to sign transaction", {
|
|
49
|
+
cause: e as Error,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (!sigDict) {
|
|
53
|
+
throw new SolanaSignerError(
|
|
54
|
+
"TransactionPartialSigner returned no signatures",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const sig = sigDict[signer.address];
|
|
59
|
+
if (!sig) {
|
|
60
|
+
throw new SolanaSignerError(
|
|
61
|
+
`TransactionPartialSigner did not produce a signature for ${signer.address}`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (sig.length !== 64) {
|
|
65
|
+
throw new SolanaSignerError(
|
|
66
|
+
`Expected a 64-byte Ed25519 signature but received ${sig.length} bytes`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const slotIndex = await findSignerSlot(transaction, signer.address);
|
|
71
|
+
if (slotIndex < 0) {
|
|
72
|
+
throw new SolanaSignerError(
|
|
73
|
+
`Signer ${signer.address} is not a required signer in this transaction`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const signedTx = new Uint8Array(transaction);
|
|
78
|
+
signedTx.set(sig, 1 + slotIndex * 64);
|
|
79
|
+
return { signedTransaction: signedTx };
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|