Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/soft-cameras-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@thirdweb-dev/vault-sdk": minor
---

Added Vault operations support for Solana.
14 changes: 1 addition & 13 deletions packages/vault-sdk/biome.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
"extends": "//",
"overrides": [
{
"assist": {
"actions": {
"source": {
"useSortedKeys": "off"
}
}
},
"includes": ["package.json"]
}
]
"extends": "//"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix invalid extends path in Biome config

Setting "extends": "//" points Biome at a non-existent root-level config, so every biome run will fail to load this package’s rules. Drop the property or replace it with a valid preset path.

-  "extends": "//"
+  "extends": []
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"extends": "//"
"extends": []
🤖 Prompt for AI Agents
In packages/vault-sdk/biome.json around line 3, the "extends": "//" entry points
to a non-existent root config; remove the "extends" property or replace it with
a valid Biome preset path (for example a workspace-relative preset or an
official preset name) so Biome can locate and load the rules correctly; update
the file accordingly and run Biome to verify the config loads.

}
11 changes: 10 additions & 1 deletion packages/vault-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,20 @@
"@noble/ciphers": "^1.2.1",
"@noble/curves": "1.8.2",
"@noble/hashes": "1.7.2",
"@solana/addresses": "^3.0.0",
"@solana/keys": "^3.0.0",
"@solana/kit": "^4.0.0",
"@solana/rpc": "^3.0.0",
"@solana/transactions": "^3.0.0",
"abitype": "1.0.8",
"jose": "6.0.11"
},
"devDependencies": {
"@biomejs/biome": "2.0.6",
"rimraf": "6.0.1"
"@solana-program/system": "^0.8.1",
"bs58": "^6.0.0",
"rimraf": "6.0.1",
"vitest": "3.2.4"
},
"engines": {
"node": ">=18"
Expand Down Expand Up @@ -51,6 +59,7 @@
"build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json",
"build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
"clean": "rimraf dist",
"test": "vitest",
"dev": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm --watch",
"fix": "biome check ./src --fix",
"format": "biome format ./src --write",
Expand Down
8 changes: 8 additions & 0 deletions packages/vault-sdk/src/exports/thirdweb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ export {
createEoa,
createServiceAccount,
createSignedAccessToken,
createSolanaAccount,
createVaultClient,
getServiceAccount,
listAccessTokens,
listEoas,
listSolanaAccounts,
ping,
revokeAccessToken,
rotateServiceAccount,
signAuthorization,
signMessage,
signSolanaMessage,
signSolanaTransaction,
signStructuredMessage,
signTransaction,
signTypedData,
Expand All @@ -31,13 +35,15 @@ export type {
CreateAccessTokenPayload,
CreateEoaPayload,
CreateServiceAccountPayload,
CreateSolanaAccountPayload,
EncryptedPayload,
GenericPayload,
GetAccessTokensData,
GetAccessTokensOptions,
GetServiceAccountPayload,
ListAccessTokensPayload,
ListEoaPayload,
ListSolanaAccountsPayload,
Payload,
PingPayload,
PolicyComponent,
Expand All @@ -49,6 +55,8 @@ export type {
SignAuthorizationRules,
SignedAuthorization,
SignMessagePayload,
SignSolanaMessagePayload,
SignSolanaTransactionPayload,
SignStructuredMessageData,
SignStructuredMessageOptions,
SignStructuredMessagePayload,
Expand Down
103 changes: 102 additions & 1 deletion packages/vault-sdk/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@ import { x25519 } from "@noble/curves/ed25519";
import { hkdf } from "@noble/hashes/hkdf";
import { sha256 } from "@noble/hashes/sha256";
import { bytesToHex, hexToBytes, randomBytes } from "@noble/hashes/utils";

import {
address,
getBase58Encoder,
getTransactionDecoder,
getTransactionEncoder,
} from "@solana/kit";

import type { TypedData } from "abitype";
import * as jose from "jose";

import type {
CheckedSignTypedDataPayload,
CreateAccessTokenPayload,
CreateEoaPayload,
CreateServiceAccountPayload,
CreateSolanaAccountPayload,
EncryptedPayload,
GetServiceAccountPayload,
ListAccessTokensPayload,
ListEoaPayload,
ListSolanaAccountsPayload,
Payload,
PingPayload,
PolicyComponent,
Expand All @@ -23,6 +32,8 @@ import type {
RotateServiceAccountPayload,
SignAuthorizationPayload,
SignMessagePayload,
SignSolanaMessagePayload,
SignSolanaTransactionPayload,
SignStructuredMessagePayload,
SignTransactionPayload,
UnencryptedErrorResponse,
Expand Down Expand Up @@ -447,6 +458,96 @@ export function listAccessTokens({
});
}

// ========== Solana Functions ==========

export function createSolanaAccount({
client,
request: options,
}: PayloadParams<CreateSolanaAccountPayload>) {
return sendRequest<CreateSolanaAccountPayload>({
client,
request: {
operation: "solana:create",
...options,
},
});
}

export function listSolanaAccounts({
client,
request: options,
}: PayloadParams<ListSolanaAccountsPayload>) {
return sendRequest<ListSolanaAccountsPayload>({
client,
request: {
operation: "solana:list",
...options,
},
});
}

export function signSolanaTransaction({
client,
request: options,
}: PayloadParams<SignSolanaTransactionPayload>) {
return sendRequest<SignSolanaTransactionPayload>({
client,
request: {
operation: "solana:signTransaction",
...options,
},
});
}

/**
* Reconstruct a signed solana transaction from the vault signature using @solana/kit
*/
export function reconstructSolanaSignedTransaction(
base64Transaction: string,
base58Signature: string,
signerPubkey: string,
): Uint8Array {
// Decode the base64 transaction into bytes
const base64TransactionBytes = new Uint8Array(
Buffer.from(base64Transaction, "base64"),
);
// Decode the transaction to get its structure
const transactionDecoder = getTransactionDecoder();
const transaction = transactionDecoder.decode(base64TransactionBytes);

// Decode the base58 signature to bytes
const base58Encoder = getBase58Encoder();
const signatureBytes = base58Encoder.encode(base58Signature);

// Add the signature to the transaction
const signedTransaction = {
...transaction,
signatures: {
...transaction.signatures,
[address(signerPubkey)]: signatureBytes,
},
};

// Re-encode the signed transaction
const transactionEncoder = getTransactionEncoder();
const signedTransactionBytes = transactionEncoder.encode(signedTransaction);

return new Uint8Array(signedTransactionBytes);
}

export function signSolanaMessage({
client,
request: options,
}: PayloadParams<SignSolanaMessagePayload>) {
return sendRequest<SignSolanaMessagePayload>({
client,
request: {
operation: "solana:signMessage",
...options,
},
});
}

const SIGNED_TOKEN_PREFIX = "vt_sat_";
const DEFAULT_SIGNING_CONTEXT = "encryption"; // Default context for HKDF

Expand Down
Loading
Loading