shell-sdk 0.1.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.
- package/LICENSE +21 -0
- package/README.md +773 -0
- package/dist/adapters.d.ts +155 -0
- package/dist/adapters.js +191 -0
- package/dist/address.d.ts +119 -0
- package/dist/address.js +220 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/keystore.d.ts +99 -0
- package/dist/keystore.js +166 -0
- package/dist/provider.d.ts +204 -0
- package/dist/provider.js +208 -0
- package/dist/signer.d.ts +161 -0
- package/dist/signer.js +188 -0
- package/dist/system-contracts.d.ts +65 -0
- package/dist/system-contracts.js +105 -0
- package/dist/transactions.d.ts +208 -0
- package/dist/transactions.js +250 -0
- package/dist/types.d.ts +140 -0
- package/dist/types.js +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import type { AddressLike, HexString, ShellSignature, ShellTransactionRequest, SignedShellTransaction, SignatureTypeName } from "./types.js";
|
|
2
|
+
/** Default transaction type: `2` (EIP-1559). */
|
|
3
|
+
export declare const DEFAULT_TX_TYPE = 2;
|
|
4
|
+
/** Default gas limit for simple SHELL token transfers (`21_000`). */
|
|
5
|
+
export declare const DEFAULT_TRANSFER_GAS_LIMIT = 21000;
|
|
6
|
+
/** Default gas limit for system contract calls (`100_000`). */
|
|
7
|
+
export declare const DEFAULT_SYSTEM_GAS_LIMIT = 100000;
|
|
8
|
+
/** Default EIP-1559 max fee per gas: `1_000_000_000` wei (1 Gwei). */
|
|
9
|
+
export declare const DEFAULT_MAX_FEE_PER_GAS = 1000000000;
|
|
10
|
+
/** Default EIP-1559 priority fee (tip) per gas: `100_000_000` wei (0.1 Gwei). */
|
|
11
|
+
export declare const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100000000;
|
|
12
|
+
/** Options accepted by {@link buildTransaction}. */
|
|
13
|
+
export interface BuildTransactionOptions {
|
|
14
|
+
/** EIP-155 chain ID. Devnet = 424242. */
|
|
15
|
+
chainId: number;
|
|
16
|
+
/** Sender account nonce. */
|
|
17
|
+
nonce: number;
|
|
18
|
+
/** Recipient address, or `null` for contract deployment. */
|
|
19
|
+
to: AddressLike | null;
|
|
20
|
+
/** Transfer value in wei. Defaults to `0n`. */
|
|
21
|
+
value?: bigint;
|
|
22
|
+
/** ABI-encoded calldata. Defaults to `"0x"`. */
|
|
23
|
+
data?: HexString;
|
|
24
|
+
/** Gas limit. Defaults to {@link DEFAULT_TRANSFER_GAS_LIMIT}. */
|
|
25
|
+
gasLimit?: number;
|
|
26
|
+
/** EIP-1559 max fee per gas in wei. Defaults to {@link DEFAULT_MAX_FEE_PER_GAS}. */
|
|
27
|
+
maxFeePerGas?: number;
|
|
28
|
+
/** EIP-1559 priority fee in wei. Defaults to {@link DEFAULT_MAX_PRIORITY_FEE_PER_GAS}. */
|
|
29
|
+
maxPriorityFeePerGas?: number;
|
|
30
|
+
/** Transaction type. Defaults to {@link DEFAULT_TX_TYPE}. */
|
|
31
|
+
txType?: number;
|
|
32
|
+
/** Optional EIP-2930 access list. */
|
|
33
|
+
accessList?: ShellTransactionRequest["access_list"];
|
|
34
|
+
/** EIP-4844 max fee per blob gas. */
|
|
35
|
+
maxFeePerBlobGas?: number | null;
|
|
36
|
+
/** EIP-4844 blob versioned hashes. */
|
|
37
|
+
blobVersionedHashes?: HexString[] | null;
|
|
38
|
+
}
|
|
39
|
+
/** Options accepted by {@link buildSignedTransaction}. */
|
|
40
|
+
export interface BuildSignedTransactionOptions {
|
|
41
|
+
/** Sender address (pq1… bech32m form). */
|
|
42
|
+
from: AddressLike;
|
|
43
|
+
/** The unsigned transaction payload. */
|
|
44
|
+
tx: ShellTransactionRequest;
|
|
45
|
+
/** Raw signature bytes. */
|
|
46
|
+
signature: Uint8Array | number[];
|
|
47
|
+
/** Algorithm that produced the signature. */
|
|
48
|
+
signatureType: SignatureTypeName;
|
|
49
|
+
/** Optional public key bytes to embed as `sender_pubkey`. */
|
|
50
|
+
senderPubkey?: Uint8Array | number[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Low-level transaction builder that maps camelCase options to the
|
|
54
|
+
* snake_case wire format expected by the Shell node.
|
|
55
|
+
*
|
|
56
|
+
* Prefer the higher-level helpers ({@link buildTransferTransaction},
|
|
57
|
+
* {@link buildRotateKeyTransaction}, etc.) for common use cases.
|
|
58
|
+
*
|
|
59
|
+
* @param options - Transaction fields; all optional fields fall back to safe defaults.
|
|
60
|
+
* @returns A `ShellTransactionRequest` ready for signing.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildTransaction(options: BuildTransactionOptions): ShellTransactionRequest;
|
|
63
|
+
/**
|
|
64
|
+
* Build a SHELL token transfer transaction (type-2 EIP-1559).
|
|
65
|
+
*
|
|
66
|
+
* Sets `data` to `"0x"` and applies the transfer gas limit default.
|
|
67
|
+
*
|
|
68
|
+
* @param options - Transfer options. `to` is required; `value` defaults to `0n`.
|
|
69
|
+
* @returns A `ShellTransactionRequest` for a plain token transfer.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```typescript
|
|
73
|
+
* import { parseEther } from "viem";
|
|
74
|
+
*
|
|
75
|
+
* const tx = buildTransferTransaction({
|
|
76
|
+
* chainId: 424242,
|
|
77
|
+
* nonce: 0,
|
|
78
|
+
* to: "pq1recipient…",
|
|
79
|
+
* value: parseEther("1.5"),
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function buildTransferTransaction(options: Omit<BuildTransactionOptions, "data" | "to"> & {
|
|
84
|
+
to: AddressLike;
|
|
85
|
+
}): ShellTransactionRequest;
|
|
86
|
+
/**
|
|
87
|
+
* Build a transaction directed at the AccountManager system contract.
|
|
88
|
+
*
|
|
89
|
+
* Sets `to` to {@link accountManagerAddress}, `value` to `0n`, and applies
|
|
90
|
+
* the system gas limit default. Used internally by the higher-level system
|
|
91
|
+
* transaction builders.
|
|
92
|
+
*
|
|
93
|
+
* @param options - Must include `data` (ABI-encoded calldata); `to` and `value` are fixed.
|
|
94
|
+
* @returns A `ShellTransactionRequest` targeting the AccountManager.
|
|
95
|
+
*/
|
|
96
|
+
export declare function buildSystemTransaction(options: Omit<BuildTransactionOptions, "to" | "value"> & {
|
|
97
|
+
data: HexString;
|
|
98
|
+
}): ShellTransactionRequest;
|
|
99
|
+
/**
|
|
100
|
+
* Build a `rotateKey` transaction that replaces the signing key for the
|
|
101
|
+
* sender's account.
|
|
102
|
+
*
|
|
103
|
+
* After this transaction is confirmed, the account can only be controlled
|
|
104
|
+
* by the new private key.
|
|
105
|
+
*
|
|
106
|
+
* @param options.chainId - EIP-155 chain ID.
|
|
107
|
+
* @param options.nonce - Sender nonce.
|
|
108
|
+
* @param options.publicKey - New public key bytes.
|
|
109
|
+
* @param options.algorithmId - Numeric algorithm ID for the new key (0/1/2).
|
|
110
|
+
* @param options.gasLimit - Override the default system gas limit.
|
|
111
|
+
* @returns A `ShellTransactionRequest` that calls `rotateKey(bytes,uint8)` on AccountManager.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const tx = buildRotateKeyTransaction({
|
|
116
|
+
* chainId: 424242,
|
|
117
|
+
* nonce: 5,
|
|
118
|
+
* publicKey: newAdapter.getPublicKey(),
|
|
119
|
+
* algorithmId: 1, // MlDsa65
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export declare function buildRotateKeyTransaction(options: {
|
|
124
|
+
chainId: number;
|
|
125
|
+
nonce: number;
|
|
126
|
+
publicKey: Uint8Array;
|
|
127
|
+
algorithmId: number;
|
|
128
|
+
gasLimit?: number;
|
|
129
|
+
}): ShellTransactionRequest;
|
|
130
|
+
/**
|
|
131
|
+
* Build a `setValidationCode` transaction that attaches a custom EVM
|
|
132
|
+
* validation contract to the sender's account (smart account / AA).
|
|
133
|
+
*
|
|
134
|
+
* @param options.chainId - EIP-155 chain ID.
|
|
135
|
+
* @param options.nonce - Sender nonce.
|
|
136
|
+
* @param options.codeHash - `bytes32` hash of the validation contract.
|
|
137
|
+
* @param options.gasLimit - Override the default system gas limit.
|
|
138
|
+
* @returns A `ShellTransactionRequest` that calls `setValidationCode(bytes32)`.
|
|
139
|
+
*/
|
|
140
|
+
export declare function buildSetValidationCodeTransaction(options: {
|
|
141
|
+
chainId: number;
|
|
142
|
+
nonce: number;
|
|
143
|
+
codeHash: HexString;
|
|
144
|
+
gasLimit?: number;
|
|
145
|
+
}): ShellTransactionRequest;
|
|
146
|
+
/**
|
|
147
|
+
* Build a `clearValidationCode` transaction that removes the custom
|
|
148
|
+
* validation contract and reverts the account to default PQ key validation.
|
|
149
|
+
*
|
|
150
|
+
* @param options.chainId - EIP-155 chain ID.
|
|
151
|
+
* @param options.nonce - Sender nonce.
|
|
152
|
+
* @param options.gasLimit - Override the default system gas limit.
|
|
153
|
+
* @returns A `ShellTransactionRequest` that calls `clearValidationCode()`.
|
|
154
|
+
*/
|
|
155
|
+
export declare function buildClearValidationCodeTransaction(options: {
|
|
156
|
+
chainId: number;
|
|
157
|
+
nonce: number;
|
|
158
|
+
gasLimit?: number;
|
|
159
|
+
}): ShellTransactionRequest;
|
|
160
|
+
/**
|
|
161
|
+
* Build a {@link ShellSignature} object from raw signature bytes.
|
|
162
|
+
*
|
|
163
|
+
* @param signatureType - The algorithm that produced the signature.
|
|
164
|
+
* @param signature - Raw signature bytes (Uint8Array or number[]).
|
|
165
|
+
* @returns A `ShellSignature` with `sig_type` and `data`.
|
|
166
|
+
*/
|
|
167
|
+
export declare function buildSignature(signatureType: SignatureTypeName, signature: Uint8Array | number[]): ShellSignature;
|
|
168
|
+
/**
|
|
169
|
+
* Assemble a {@link SignedShellTransaction} from individual components.
|
|
170
|
+
*
|
|
171
|
+
* In practice, use {@link ShellSigner.buildSignedTransaction} which handles
|
|
172
|
+
* signing and assembly in one step.
|
|
173
|
+
*
|
|
174
|
+
* @param options - Sender address, unsigned tx, raw signature bytes, and algorithm name.
|
|
175
|
+
* @returns A complete `SignedShellTransaction` ready to broadcast.
|
|
176
|
+
*/
|
|
177
|
+
export declare function buildSignedTransaction(options: BuildSignedTransactionOptions): SignedShellTransaction;
|
|
178
|
+
/**
|
|
179
|
+
* Encode a `Uint8Array` as a `0x`-prefixed hex string.
|
|
180
|
+
*
|
|
181
|
+
* @param bytes - Bytes to encode.
|
|
182
|
+
* @returns A `HexString`.
|
|
183
|
+
*/
|
|
184
|
+
export declare function hexBytes(bytes: Uint8Array): HexString;
|
|
185
|
+
/**
|
|
186
|
+
* RLP-encode a `ShellTransactionRequest` and return its keccak256 hash.
|
|
187
|
+
*
|
|
188
|
+
* This is the signing hash that must be passed to `ShellSigner.buildSignedTransaction`
|
|
189
|
+
* (or `signer.sign`). Shell Chain computes it identically on the node side as
|
|
190
|
+
* `keccak256(RLP(tx))` — the same scheme as Ethereum EIP-1559 signing.
|
|
191
|
+
*
|
|
192
|
+
* **Encoding order** (EIP-2718 type-2 fields):
|
|
193
|
+
* chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit,
|
|
194
|
+
* to, value, data, accessList, maxFeePerBlobGas (if present), blobVersionedHashes (if present)
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```typescript
|
|
198
|
+
* import { buildTransferTransaction, hashTransaction } from "shell-sdk/transactions";
|
|
199
|
+
*
|
|
200
|
+
* const tx = buildTransferTransaction({ chainId: 424242, nonce: 0, to: "pq1…", value: 1n });
|
|
201
|
+
* const txHash = hashTransaction(tx);
|
|
202
|
+
* const signed = await signer.buildSignedTransaction({ tx, txHash });
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* @param tx - The unsigned transaction to hash.
|
|
206
|
+
* @returns 32-byte keccak256 hash as a `Uint8Array`.
|
|
207
|
+
*/
|
|
208
|
+
export declare function hashTransaction(tx: ShellTransactionRequest): Uint8Array;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transaction builders for Shell Chain.
|
|
3
|
+
*
|
|
4
|
+
* Provides typed helpers for constructing `ShellTransactionRequest` objects
|
|
5
|
+
* for common operations: token transfers, system contract calls, key rotation,
|
|
6
|
+
* and custom validation code management.
|
|
7
|
+
*
|
|
8
|
+
* @module transactions
|
|
9
|
+
*/
|
|
10
|
+
import { bytesToHex, keccak256, toRlp, numberToHex, hexToBytes } from "viem";
|
|
11
|
+
import { accountManagerAddress, encodeClearValidationCodeCalldata, encodeRotateKeyCalldata, encodeSetValidationCodeCalldata, } from "./system-contracts.js";
|
|
12
|
+
/** Default transaction type: `2` (EIP-1559). */
|
|
13
|
+
export const DEFAULT_TX_TYPE = 2;
|
|
14
|
+
/** Default gas limit for simple SHELL token transfers (`21_000`). */
|
|
15
|
+
export const DEFAULT_TRANSFER_GAS_LIMIT = 21_000;
|
|
16
|
+
/** Default gas limit for system contract calls (`100_000`). */
|
|
17
|
+
export const DEFAULT_SYSTEM_GAS_LIMIT = 100_000;
|
|
18
|
+
/** Default EIP-1559 max fee per gas: `1_000_000_000` wei (1 Gwei). */
|
|
19
|
+
export const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000;
|
|
20
|
+
/** Default EIP-1559 priority fee (tip) per gas: `100_000_000` wei (0.1 Gwei). */
|
|
21
|
+
export const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000;
|
|
22
|
+
function toByteArray(bytes) {
|
|
23
|
+
return Array.from(bytes);
|
|
24
|
+
}
|
|
25
|
+
function toHexData(data) {
|
|
26
|
+
return data ?? "0x";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Low-level transaction builder that maps camelCase options to the
|
|
30
|
+
* snake_case wire format expected by the Shell node.
|
|
31
|
+
*
|
|
32
|
+
* Prefer the higher-level helpers ({@link buildTransferTransaction},
|
|
33
|
+
* {@link buildRotateKeyTransaction}, etc.) for common use cases.
|
|
34
|
+
*
|
|
35
|
+
* @param options - Transaction fields; all optional fields fall back to safe defaults.
|
|
36
|
+
* @returns A `ShellTransactionRequest` ready for signing.
|
|
37
|
+
*/
|
|
38
|
+
export function buildTransaction(options) {
|
|
39
|
+
return {
|
|
40
|
+
chain_id: options.chainId,
|
|
41
|
+
nonce: options.nonce,
|
|
42
|
+
to: options.to,
|
|
43
|
+
value: `0x${(options.value ?? 0n).toString(16)}`,
|
|
44
|
+
data: toHexData(options.data),
|
|
45
|
+
gas_limit: options.gasLimit ?? DEFAULT_TRANSFER_GAS_LIMIT,
|
|
46
|
+
max_fee_per_gas: options.maxFeePerGas ?? DEFAULT_MAX_FEE_PER_GAS,
|
|
47
|
+
max_priority_fee_per_gas: options.maxPriorityFeePerGas ?? DEFAULT_MAX_PRIORITY_FEE_PER_GAS,
|
|
48
|
+
access_list: options.accessList ?? null,
|
|
49
|
+
tx_type: options.txType ?? DEFAULT_TX_TYPE,
|
|
50
|
+
max_fee_per_blob_gas: options.maxFeePerBlobGas ?? null,
|
|
51
|
+
blob_versioned_hashes: options.blobVersionedHashes ?? null,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Build a SHELL token transfer transaction (type-2 EIP-1559).
|
|
56
|
+
*
|
|
57
|
+
* Sets `data` to `"0x"` and applies the transfer gas limit default.
|
|
58
|
+
*
|
|
59
|
+
* @param options - Transfer options. `to` is required; `value` defaults to `0n`.
|
|
60
|
+
* @returns A `ShellTransactionRequest` for a plain token transfer.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* import { parseEther } from "viem";
|
|
65
|
+
*
|
|
66
|
+
* const tx = buildTransferTransaction({
|
|
67
|
+
* chainId: 424242,
|
|
68
|
+
* nonce: 0,
|
|
69
|
+
* to: "pq1recipient…",
|
|
70
|
+
* value: parseEther("1.5"),
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export function buildTransferTransaction(options) {
|
|
75
|
+
return buildTransaction({
|
|
76
|
+
...options,
|
|
77
|
+
data: "0x",
|
|
78
|
+
gasLimit: options.gasLimit ?? DEFAULT_TRANSFER_GAS_LIMIT,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build a transaction directed at the AccountManager system contract.
|
|
83
|
+
*
|
|
84
|
+
* Sets `to` to {@link accountManagerAddress}, `value` to `0n`, and applies
|
|
85
|
+
* the system gas limit default. Used internally by the higher-level system
|
|
86
|
+
* transaction builders.
|
|
87
|
+
*
|
|
88
|
+
* @param options - Must include `data` (ABI-encoded calldata); `to` and `value` are fixed.
|
|
89
|
+
* @returns A `ShellTransactionRequest` targeting the AccountManager.
|
|
90
|
+
*/
|
|
91
|
+
export function buildSystemTransaction(options) {
|
|
92
|
+
return buildTransaction({
|
|
93
|
+
...options,
|
|
94
|
+
to: accountManagerAddress,
|
|
95
|
+
value: 0n,
|
|
96
|
+
gasLimit: options.gasLimit ?? DEFAULT_SYSTEM_GAS_LIMIT,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build a `rotateKey` transaction that replaces the signing key for the
|
|
101
|
+
* sender's account.
|
|
102
|
+
*
|
|
103
|
+
* After this transaction is confirmed, the account can only be controlled
|
|
104
|
+
* by the new private key.
|
|
105
|
+
*
|
|
106
|
+
* @param options.chainId - EIP-155 chain ID.
|
|
107
|
+
* @param options.nonce - Sender nonce.
|
|
108
|
+
* @param options.publicKey - New public key bytes.
|
|
109
|
+
* @param options.algorithmId - Numeric algorithm ID for the new key (0/1/2).
|
|
110
|
+
* @param options.gasLimit - Override the default system gas limit.
|
|
111
|
+
* @returns A `ShellTransactionRequest` that calls `rotateKey(bytes,uint8)` on AccountManager.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const tx = buildRotateKeyTransaction({
|
|
116
|
+
* chainId: 424242,
|
|
117
|
+
* nonce: 5,
|
|
118
|
+
* publicKey: newAdapter.getPublicKey(),
|
|
119
|
+
* algorithmId: 1, // MlDsa65
|
|
120
|
+
* });
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
export function buildRotateKeyTransaction(options) {
|
|
124
|
+
return buildSystemTransaction({
|
|
125
|
+
chainId: options.chainId,
|
|
126
|
+
nonce: options.nonce,
|
|
127
|
+
data: encodeRotateKeyCalldata(options.publicKey, options.algorithmId),
|
|
128
|
+
gasLimit: options.gasLimit ?? DEFAULT_SYSTEM_GAS_LIMIT,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Build a `setValidationCode` transaction that attaches a custom EVM
|
|
133
|
+
* validation contract to the sender's account (smart account / AA).
|
|
134
|
+
*
|
|
135
|
+
* @param options.chainId - EIP-155 chain ID.
|
|
136
|
+
* @param options.nonce - Sender nonce.
|
|
137
|
+
* @param options.codeHash - `bytes32` hash of the validation contract.
|
|
138
|
+
* @param options.gasLimit - Override the default system gas limit.
|
|
139
|
+
* @returns A `ShellTransactionRequest` that calls `setValidationCode(bytes32)`.
|
|
140
|
+
*/
|
|
141
|
+
export function buildSetValidationCodeTransaction(options) {
|
|
142
|
+
return buildSystemTransaction({
|
|
143
|
+
chainId: options.chainId,
|
|
144
|
+
nonce: options.nonce,
|
|
145
|
+
data: encodeSetValidationCodeCalldata(options.codeHash),
|
|
146
|
+
gasLimit: options.gasLimit ?? DEFAULT_SYSTEM_GAS_LIMIT,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a `clearValidationCode` transaction that removes the custom
|
|
151
|
+
* validation contract and reverts the account to default PQ key validation.
|
|
152
|
+
*
|
|
153
|
+
* @param options.chainId - EIP-155 chain ID.
|
|
154
|
+
* @param options.nonce - Sender nonce.
|
|
155
|
+
* @param options.gasLimit - Override the default system gas limit.
|
|
156
|
+
* @returns A `ShellTransactionRequest` that calls `clearValidationCode()`.
|
|
157
|
+
*/
|
|
158
|
+
export function buildClearValidationCodeTransaction(options) {
|
|
159
|
+
return buildSystemTransaction({
|
|
160
|
+
chainId: options.chainId,
|
|
161
|
+
nonce: options.nonce,
|
|
162
|
+
data: encodeClearValidationCodeCalldata(),
|
|
163
|
+
gasLimit: options.gasLimit ?? DEFAULT_SYSTEM_GAS_LIMIT,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Build a {@link ShellSignature} object from raw signature bytes.
|
|
168
|
+
*
|
|
169
|
+
* @param signatureType - The algorithm that produced the signature.
|
|
170
|
+
* @param signature - Raw signature bytes (Uint8Array or number[]).
|
|
171
|
+
* @returns A `ShellSignature` with `sig_type` and `data`.
|
|
172
|
+
*/
|
|
173
|
+
export function buildSignature(signatureType, signature) {
|
|
174
|
+
return {
|
|
175
|
+
sig_type: signatureType,
|
|
176
|
+
data: toByteArray(signature),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Assemble a {@link SignedShellTransaction} from individual components.
|
|
181
|
+
*
|
|
182
|
+
* In practice, use {@link ShellSigner.buildSignedTransaction} which handles
|
|
183
|
+
* signing and assembly in one step.
|
|
184
|
+
*
|
|
185
|
+
* @param options - Sender address, unsigned tx, raw signature bytes, and algorithm name.
|
|
186
|
+
* @returns A complete `SignedShellTransaction` ready to broadcast.
|
|
187
|
+
*/
|
|
188
|
+
export function buildSignedTransaction(options) {
|
|
189
|
+
return {
|
|
190
|
+
from: options.from,
|
|
191
|
+
tx: options.tx,
|
|
192
|
+
signature: buildSignature(options.signatureType, options.signature),
|
|
193
|
+
sender_pubkey: options.senderPubkey ? toByteArray(options.senderPubkey) : null,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Encode a `Uint8Array` as a `0x`-prefixed hex string.
|
|
198
|
+
*
|
|
199
|
+
* @param bytes - Bytes to encode.
|
|
200
|
+
* @returns A `HexString`.
|
|
201
|
+
*/
|
|
202
|
+
export function hexBytes(bytes) {
|
|
203
|
+
return bytesToHex(bytes);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* RLP-encode a `ShellTransactionRequest` and return its keccak256 hash.
|
|
207
|
+
*
|
|
208
|
+
* This is the signing hash that must be passed to `ShellSigner.buildSignedTransaction`
|
|
209
|
+
* (or `signer.sign`). Shell Chain computes it identically on the node side as
|
|
210
|
+
* `keccak256(RLP(tx))` — the same scheme as Ethereum EIP-1559 signing.
|
|
211
|
+
*
|
|
212
|
+
* **Encoding order** (EIP-2718 type-2 fields):
|
|
213
|
+
* chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit,
|
|
214
|
+
* to, value, data, accessList, maxFeePerBlobGas (if present), blobVersionedHashes (if present)
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* import { buildTransferTransaction, hashTransaction } from "shell-sdk/transactions";
|
|
219
|
+
*
|
|
220
|
+
* const tx = buildTransferTransaction({ chainId: 424242, nonce: 0, to: "pq1…", value: 1n });
|
|
221
|
+
* const txHash = hashTransaction(tx);
|
|
222
|
+
* const signed = await signer.buildSignedTransaction({ tx, txHash });
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @param tx - The unsigned transaction to hash.
|
|
226
|
+
* @returns 32-byte keccak256 hash as a `Uint8Array`.
|
|
227
|
+
*/
|
|
228
|
+
export function hashTransaction(tx) {
|
|
229
|
+
const to = tx.to ? hexToBytes(tx.to.startsWith("0x") ? tx.to : `0x${tx.to}`) : new Uint8Array(0);
|
|
230
|
+
const data = hexToBytes(tx.data);
|
|
231
|
+
const value = hexToBytes(tx.value);
|
|
232
|
+
const fields = [
|
|
233
|
+
numberToHex(tx.chain_id),
|
|
234
|
+
numberToHex(tx.nonce),
|
|
235
|
+
numberToHex(tx.max_priority_fee_per_gas),
|
|
236
|
+
numberToHex(tx.max_fee_per_gas),
|
|
237
|
+
numberToHex(tx.gas_limit),
|
|
238
|
+
bytesToHex(to),
|
|
239
|
+
bytesToHex(value),
|
|
240
|
+
bytesToHex(data),
|
|
241
|
+
"0x", // empty access list
|
|
242
|
+
];
|
|
243
|
+
if (tx.max_fee_per_blob_gas != null) {
|
|
244
|
+
fields.push(numberToHex(tx.max_fee_per_blob_gas));
|
|
245
|
+
fields.push("0x"); // empty blob versioned hashes
|
|
246
|
+
}
|
|
247
|
+
const rlpEncoded = toRlp(fields);
|
|
248
|
+
const hash = hexToBytes(keccak256(rlpEncoded));
|
|
249
|
+
return hash;
|
|
250
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/** A `0x`-prefixed hex string, e.g. `"0xdeadbeef"`. */
|
|
2
|
+
export type HexString = `0x${string}`;
|
|
3
|
+
/** Any string accepted as an address — either a `pq1…` bech32m address or a `0x…` hex address. */
|
|
4
|
+
export type AddressLike = string;
|
|
5
|
+
/** A single entry in an EIP-2930 access list. */
|
|
6
|
+
export interface ShellAccessListItem {
|
|
7
|
+
address: AddressLike;
|
|
8
|
+
storage_keys: HexString[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Wire format for a Shell Chain transaction, sent as part of a {@link SignedShellTransaction}.
|
|
12
|
+
*
|
|
13
|
+
* Mirrors the JSON structure expected by the `shell_sendTransaction` RPC method.
|
|
14
|
+
* Use the builder helpers in `transactions.ts` rather than constructing this object manually.
|
|
15
|
+
*/
|
|
16
|
+
export interface ShellTransactionRequest {
|
|
17
|
+
/** EIP-155 chain ID. Devnet = 424242. */
|
|
18
|
+
chain_id: number;
|
|
19
|
+
/** Sender account nonce. */
|
|
20
|
+
nonce: number;
|
|
21
|
+
/** Recipient address (pq1… or 0x…), or `null` for contract deployment. */
|
|
22
|
+
to: AddressLike | null;
|
|
23
|
+
/** Transfer value as a hex-encoded bigint string, e.g. `"0xde0b6b3a7640000"`. */
|
|
24
|
+
value: string;
|
|
25
|
+
/** ABI-encoded call data, or `"0x"` for plain transfers. */
|
|
26
|
+
data: HexString;
|
|
27
|
+
/** Maximum gas units the transaction may consume. */
|
|
28
|
+
gas_limit: number;
|
|
29
|
+
/** EIP-1559 maximum fee per gas unit (in wei). */
|
|
30
|
+
max_fee_per_gas: number;
|
|
31
|
+
/** EIP-1559 priority fee (tip) per gas unit (in wei). */
|
|
32
|
+
max_priority_fee_per_gas: number;
|
|
33
|
+
/** Optional EIP-2930 access list. */
|
|
34
|
+
access_list?: ShellAccessListItem[] | null;
|
|
35
|
+
/** Transaction type; defaults to `2` (EIP-1559). */
|
|
36
|
+
tx_type?: number;
|
|
37
|
+
/** EIP-4844 max fee per blob gas unit. */
|
|
38
|
+
max_fee_per_blob_gas?: number | null;
|
|
39
|
+
/** EIP-4844 blob versioned hashes. */
|
|
40
|
+
blob_versioned_hashes?: HexString[] | null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The name of a supported post-quantum signature algorithm.
|
|
44
|
+
*
|
|
45
|
+
* - `"Dilithium3"` — Round-3 Dilithium (algorithm ID 0); uses the ML-DSA-65 implementation as a stand-in.
|
|
46
|
+
* - `"MlDsa65"` — NIST FIPS 204 ML-DSA-65 (algorithm ID 1).
|
|
47
|
+
* - `"SphincsSha2256f"` — NIST FIPS 205 SLH-DSA-SHA2-256f (algorithm ID 2).
|
|
48
|
+
*/
|
|
49
|
+
export type SignatureTypeName = "Dilithium3" | "MlDsa65" | "SphincsSha2256f";
|
|
50
|
+
/**
|
|
51
|
+
* A post-quantum signature attached to a transaction.
|
|
52
|
+
*
|
|
53
|
+
* `data` contains the raw signature bytes serialised as a plain number array
|
|
54
|
+
* to ensure JSON compatibility without base64 encoding overhead.
|
|
55
|
+
*/
|
|
56
|
+
export interface ShellSignature {
|
|
57
|
+
/** Algorithm that produced this signature. */
|
|
58
|
+
sig_type: SignatureTypeName;
|
|
59
|
+
/** Raw signature bytes as a JS number array. */
|
|
60
|
+
data: number[];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A fully-signed Shell Chain transaction ready to broadcast via `shell_sendTransaction`.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const signed: SignedShellTransaction = await signer.buildSignedTransaction({ tx, txHash });
|
|
68
|
+
* const hash = await provider.sendTransaction(signed);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export interface SignedShellTransaction {
|
|
72
|
+
/** Sender address (pq1… bech32m form). */
|
|
73
|
+
from: AddressLike;
|
|
74
|
+
/** The unsigned transaction payload. */
|
|
75
|
+
tx: ShellTransactionRequest;
|
|
76
|
+
/** PQ signature produced by the sender's private key. */
|
|
77
|
+
signature: ShellSignature;
|
|
78
|
+
/**
|
|
79
|
+
* Raw public key bytes of the sender.
|
|
80
|
+
* Required when the account has not yet appeared on-chain so the node can
|
|
81
|
+
* verify the address derivation. Pass `null` for subsequent transactions.
|
|
82
|
+
*/
|
|
83
|
+
sender_pubkey?: number[] | null;
|
|
84
|
+
}
|
|
85
|
+
/** Paginated response from `shell_getTransactionsByAddress`. */
|
|
86
|
+
export interface ShellTxByAddressPage {
|
|
87
|
+
address: AddressLike;
|
|
88
|
+
page: number;
|
|
89
|
+
limit: number;
|
|
90
|
+
total: number;
|
|
91
|
+
transactions: unknown[];
|
|
92
|
+
}
|
|
93
|
+
/** Parameters for `shell_sendTransaction`. */
|
|
94
|
+
export interface ShellSendTransactionParams {
|
|
95
|
+
signedTransaction: SignedShellTransaction;
|
|
96
|
+
}
|
|
97
|
+
/** argon2id KDF parameters stored in a Shell keystore file. */
|
|
98
|
+
export interface ShellKdfParams {
|
|
99
|
+
/** Memory cost in KiB (argon2id `m`). */
|
|
100
|
+
m_cost: number;
|
|
101
|
+
/** Time cost / iteration count (argon2id `t`). */
|
|
102
|
+
t_cost: number;
|
|
103
|
+
/** Parallelism factor (argon2id `p`). */
|
|
104
|
+
p_cost: number;
|
|
105
|
+
/** Hex-encoded random salt. */
|
|
106
|
+
salt: string;
|
|
107
|
+
}
|
|
108
|
+
/** xchacha20-poly1305 cipher parameters stored in a Shell keystore file. */
|
|
109
|
+
export interface ShellCipherParams {
|
|
110
|
+
/** Hex-encoded 24-byte nonce. */
|
|
111
|
+
nonce: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The JSON structure of an encrypted Shell keystore file.
|
|
115
|
+
*
|
|
116
|
+
* Generated by the Shell CLI (`shell key generate`). Decrypt with
|
|
117
|
+
* {@link decryptKeystore} from `keystore.ts`.
|
|
118
|
+
*
|
|
119
|
+
* Plaintext layout after decryption: `[secret_key_bytes][public_key_bytes]`.
|
|
120
|
+
*/
|
|
121
|
+
export interface ShellEncryptedKey {
|
|
122
|
+
/** Schema version (currently `1`). */
|
|
123
|
+
version: number;
|
|
124
|
+
/** bech32m `pq1…` address corresponding to the encrypted key. */
|
|
125
|
+
address: string;
|
|
126
|
+
/** Key algorithm identifier string, e.g. `"mldsa65"` or `"sphincs-sha2-256f"`. */
|
|
127
|
+
key_type: string;
|
|
128
|
+
/** KDF algorithm name; currently always `"argon2id"`. */
|
|
129
|
+
kdf: string;
|
|
130
|
+
/** argon2id parameters. */
|
|
131
|
+
kdf_params: ShellKdfParams;
|
|
132
|
+
/** Cipher algorithm name; currently always `"xchacha20-poly1305"`. */
|
|
133
|
+
cipher: string;
|
|
134
|
+
/** Cipher nonce. */
|
|
135
|
+
cipher_params: ShellCipherParams;
|
|
136
|
+
/** Hex-encoded authenticated ciphertext (includes poly1305 tag). */
|
|
137
|
+
ciphertext: string;
|
|
138
|
+
/** Hex-encoded raw public key bytes. */
|
|
139
|
+
public_key: string;
|
|
140
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shell-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for Shell Chain",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./address": {
|
|
15
|
+
"types": "./dist/address.d.ts",
|
|
16
|
+
"import": "./dist/address.js"
|
|
17
|
+
},
|
|
18
|
+
"./provider": {
|
|
19
|
+
"types": "./dist/provider.d.ts",
|
|
20
|
+
"import": "./dist/provider.js"
|
|
21
|
+
},
|
|
22
|
+
"./signer": {
|
|
23
|
+
"types": "./dist/signer.d.ts",
|
|
24
|
+
"import": "./dist/signer.js"
|
|
25
|
+
},
|
|
26
|
+
"./adapters": {
|
|
27
|
+
"types": "./dist/adapters.d.ts",
|
|
28
|
+
"import": "./dist/adapters.js"
|
|
29
|
+
},
|
|
30
|
+
"./keystore": {
|
|
31
|
+
"types": "./dist/keystore.d.ts",
|
|
32
|
+
"import": "./dist/keystore.js"
|
|
33
|
+
},
|
|
34
|
+
"./transactions": {
|
|
35
|
+
"types": "./dist/transactions.d.ts",
|
|
36
|
+
"import": "./dist/transactions.js"
|
|
37
|
+
},
|
|
38
|
+
"./system-contracts": {
|
|
39
|
+
"types": "./dist/system-contracts.d.ts",
|
|
40
|
+
"import": "./dist/system-contracts.js"
|
|
41
|
+
},
|
|
42
|
+
"./types": {
|
|
43
|
+
"types": "./dist/types.d.ts",
|
|
44
|
+
"import": "./dist/types.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist"
|
|
49
|
+
],
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc -p tsconfig.json",
|
|
52
|
+
"clean": "rm -rf dist",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"shell-chain",
|
|
57
|
+
"sdk",
|
|
58
|
+
"viem",
|
|
59
|
+
"typescript",
|
|
60
|
+
"pq"
|
|
61
|
+
],
|
|
62
|
+
"repository": {
|
|
63
|
+
"type": "git",
|
|
64
|
+
"url": "git+https://github.com/ShellDAO/shell-sdk.git"
|
|
65
|
+
},
|
|
66
|
+
"bugs": {
|
|
67
|
+
"url": "https://github.com/ShellDAO/shell-sdk/issues"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/ShellDAO/shell-sdk#readme",
|
|
70
|
+
"dependencies": {
|
|
71
|
+
"@noble/ciphers": "^2.1.1",
|
|
72
|
+
"@noble/hashes": "^1.8.0",
|
|
73
|
+
"@noble/post-quantum": "^0.6.0",
|
|
74
|
+
"@scure/base": "^1.2.6",
|
|
75
|
+
"hash-wasm": "^4.12.0",
|
|
76
|
+
"viem": "^2.39.0"
|
|
77
|
+
},
|
|
78
|
+
"devDependencies": {
|
|
79
|
+
"@types/node": "^24.0.0",
|
|
80
|
+
"typescript": "^5.9.0"
|
|
81
|
+
}
|
|
82
|
+
}
|