Skip to content

Commit 35c7d21

Browse files
authored
[Vault SDK] Add Solana operations support (#8168)
1 parent edf3aad commit 35c7d21

File tree

11 files changed

+3090
-32
lines changed

11 files changed

+3090
-32
lines changed

.changeset/soft-cameras-lay.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/vault-sdk": minor
3+
---
4+
5+
Added Vault operations support for Solana.

packages/vault-sdk/biome.json

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,4 @@
11
{
22
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
3-
"extends": "//",
4-
"overrides": [
5-
{
6-
"assist": {
7-
"actions": {
8-
"source": {
9-
"useSortedKeys": "off"
10-
}
11-
}
12-
},
13-
"includes": ["package.json"]
14-
}
15-
]
3+
"extends": "//"
164
}

packages/vault-sdk/package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,20 @@
77
"@noble/ciphers": "^1.2.1",
88
"@noble/curves": "1.8.2",
99
"@noble/hashes": "1.7.2",
10+
"@solana/addresses": "^3.0.0",
11+
"@solana/keys": "^3.0.0",
12+
"@solana/kit": "^4.0.0",
13+
"@solana/rpc": "^3.0.0",
14+
"@solana/transactions": "^3.0.0",
1015
"abitype": "1.0.8",
1116
"jose": "6.0.11"
1217
},
1318
"devDependencies": {
1419
"@biomejs/biome": "2.0.6",
15-
"rimraf": "6.0.1"
20+
"@solana-program/system": "^0.8.1",
21+
"bs58": "^6.0.0",
22+
"rimraf": "6.0.1",
23+
"vitest": "3.2.4"
1624
},
1725
"engines": {
1826
"node": ">=18"
@@ -51,6 +59,7 @@
5159
"build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json",
5260
"build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
5361
"clean": "rimraf dist",
62+
"test:solana": "vitest ./tests/solana.test.ts",
5463
"dev": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm --watch",
5564
"fix": "biome check ./src --fix",
5665
"format": "biome format ./src --write",

packages/vault-sdk/src/exports/thirdweb.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@ export {
33
createEoa,
44
createServiceAccount,
55
createSignedAccessToken,
6+
createSolanaAccount,
67
createVaultClient,
78
getServiceAccount,
89
listAccessTokens,
910
listEoas,
11+
listSolanaAccounts,
1012
ping,
1113
revokeAccessToken,
1214
rotateServiceAccount,
1315
signAuthorization,
1416
signMessage,
17+
signSolanaMessage,
18+
signSolanaTransaction,
1519
signStructuredMessage,
1620
signTransaction,
1721
signTypedData,
@@ -31,13 +35,15 @@ export type {
3135
CreateAccessTokenPayload,
3236
CreateEoaPayload,
3337
CreateServiceAccountPayload,
38+
CreateSolanaAccountPayload,
3439
EncryptedPayload,
3540
GenericPayload,
3641
GetAccessTokensData,
3742
GetAccessTokensOptions,
3843
GetServiceAccountPayload,
3944
ListAccessTokensPayload,
4045
ListEoaPayload,
46+
ListSolanaAccountsPayload,
4147
Payload,
4248
PingPayload,
4349
PolicyComponent,
@@ -49,6 +55,8 @@ export type {
4955
SignAuthorizationRules,
5056
SignedAuthorization,
5157
SignMessagePayload,
58+
SignSolanaMessagePayload,
59+
SignSolanaTransactionPayload,
5260
SignStructuredMessageData,
5361
SignStructuredMessageOptions,
5462
SignStructuredMessagePayload,

packages/vault-sdk/src/sdk.ts

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,27 @@ import { x25519 } from "@noble/curves/ed25519";
33
import { hkdf } from "@noble/hashes/hkdf";
44
import { sha256 } from "@noble/hashes/sha256";
55
import { bytesToHex, hexToBytes, randomBytes } from "@noble/hashes/utils";
6+
7+
import {
8+
address,
9+
getBase58Encoder,
10+
getTransactionDecoder,
11+
getTransactionEncoder,
12+
} from "@solana/kit";
13+
614
import type { TypedData } from "abitype";
715
import * as jose from "jose";
8-
916
import type {
1017
CheckedSignTypedDataPayload,
1118
CreateAccessTokenPayload,
1219
CreateEoaPayload,
1320
CreateServiceAccountPayload,
21+
CreateSolanaAccountPayload,
1422
EncryptedPayload,
1523
GetServiceAccountPayload,
1624
ListAccessTokensPayload,
1725
ListEoaPayload,
26+
ListSolanaAccountsPayload,
1827
Payload,
1928
PingPayload,
2029
PolicyComponent,
@@ -23,6 +32,8 @@ import type {
2332
RotateServiceAccountPayload,
2433
SignAuthorizationPayload,
2534
SignMessagePayload,
35+
SignSolanaMessagePayload,
36+
SignSolanaTransactionPayload,
2637
SignStructuredMessagePayload,
2738
SignTransactionPayload,
2839
UnencryptedErrorResponse,
@@ -447,6 +458,96 @@ export function listAccessTokens({
447458
});
448459
}
449460

461+
// ========== Solana Functions ==========
462+
463+
export function createSolanaAccount({
464+
client,
465+
request: options,
466+
}: PayloadParams<CreateSolanaAccountPayload>) {
467+
return sendRequest<CreateSolanaAccountPayload>({
468+
client,
469+
request: {
470+
operation: "solana:create",
471+
...options,
472+
},
473+
});
474+
}
475+
476+
export function listSolanaAccounts({
477+
client,
478+
request: options,
479+
}: PayloadParams<ListSolanaAccountsPayload>) {
480+
return sendRequest<ListSolanaAccountsPayload>({
481+
client,
482+
request: {
483+
operation: "solana:list",
484+
...options,
485+
},
486+
});
487+
}
488+
489+
export function signSolanaTransaction({
490+
client,
491+
request: options,
492+
}: PayloadParams<SignSolanaTransactionPayload>) {
493+
return sendRequest<SignSolanaTransactionPayload>({
494+
client,
495+
request: {
496+
operation: "solana:signTransaction",
497+
...options,
498+
},
499+
});
500+
}
501+
502+
/**
503+
* Reconstruct a signed solana transaction from the vault signature using @solana/kit
504+
*/
505+
export function reconstructSolanaSignedTransaction(
506+
base64Transaction: string,
507+
base58Signature: string,
508+
signerPubkey: string,
509+
): Uint8Array {
510+
// Decode the base64 transaction into bytes
511+
const base64TransactionBytes = new Uint8Array(
512+
Buffer.from(base64Transaction, "base64"),
513+
);
514+
// Decode the transaction to get its structure
515+
const transactionDecoder = getTransactionDecoder();
516+
const transaction = transactionDecoder.decode(base64TransactionBytes);
517+
518+
// Decode the base58 signature to bytes
519+
const base58Encoder = getBase58Encoder();
520+
const signatureBytes = base58Encoder.encode(base58Signature);
521+
522+
// Add the signature to the transaction
523+
const signedTransaction = {
524+
...transaction,
525+
signatures: {
526+
...transaction.signatures,
527+
[address(signerPubkey)]: signatureBytes,
528+
},
529+
};
530+
531+
// Re-encode the signed transaction
532+
const transactionEncoder = getTransactionEncoder();
533+
const signedTransactionBytes = transactionEncoder.encode(signedTransaction);
534+
535+
return new Uint8Array(signedTransactionBytes);
536+
}
537+
538+
export function signSolanaMessage({
539+
client,
540+
request: options,
541+
}: PayloadParams<SignSolanaMessagePayload>) {
542+
return sendRequest<SignSolanaMessagePayload>({
543+
client,
544+
request: {
545+
operation: "solana:signMessage",
546+
...options,
547+
},
548+
});
549+
}
550+
450551
const SIGNED_TOKEN_PREFIX = "vt_sat_";
451552
const DEFAULT_SIGNING_CONTEXT = "encryption"; // Default context for HKDF
452553

0 commit comments

Comments
 (0)