near-kit 0.0.0 → 0.2.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 +473 -2
- package/dist/contracts/contract.d.ts +63 -0
- package/dist/contracts/contract.d.ts.map +1 -0
- package/dist/contracts/contract.js +42 -0
- package/dist/contracts/contract.js.map +1 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +5 -0
- package/dist/contracts/index.js.map +1 -0
- package/dist/core/actions.d.ts +193 -0
- package/dist/core/actions.d.ts.map +1 -0
- package/dist/core/actions.js +195 -0
- package/dist/core/actions.js.map +1 -0
- package/dist/core/config-schemas.d.ts +179 -0
- package/dist/core/config-schemas.d.ts.map +1 -0
- package/dist/core/config-schemas.js +169 -0
- package/dist/core/config-schemas.js.map +1 -0
- package/dist/core/constants.d.ts +43 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +49 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/near.d.ts +301 -0
- package/dist/core/near.d.ts.map +1 -0
- package/dist/core/near.js +504 -0
- package/dist/core/near.js.map +1 -0
- package/dist/core/nonce-manager.d.ts +39 -0
- package/dist/core/nonce-manager.d.ts.map +1 -0
- package/dist/core/nonce-manager.js +73 -0
- package/dist/core/nonce-manager.js.map +1 -0
- package/dist/core/rpc/rpc-error-handler.d.ts +60 -0
- package/dist/core/rpc/rpc-error-handler.d.ts.map +1 -0
- package/dist/core/rpc/rpc-error-handler.js +324 -0
- package/dist/core/rpc/rpc-error-handler.js.map +1 -0
- package/dist/core/rpc/rpc-schemas.d.ts +1812 -0
- package/dist/core/rpc/rpc-schemas.d.ts.map +1 -0
- package/dist/core/rpc/rpc-schemas.js +424 -0
- package/dist/core/rpc/rpc-schemas.js.map +1 -0
- package/dist/core/rpc/rpc.d.ts +117 -0
- package/dist/core/rpc/rpc.d.ts.map +1 -0
- package/dist/core/rpc/rpc.js +325 -0
- package/dist/core/rpc/rpc.js.map +1 -0
- package/dist/core/schema.d.ts +1188 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +396 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/transaction.d.ts +390 -0
- package/dist/core/transaction.d.ts.map +1 -0
- package/dist/core/transaction.js +653 -0
- package/dist/core/transaction.js.map +1 -0
- package/dist/core/types.d.ts +271 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -0
- package/dist/errors/index.d.ts +226 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +366 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/keys/credential-schemas.d.ts +98 -0
- package/dist/keys/credential-schemas.d.ts.map +1 -0
- package/dist/keys/credential-schemas.js +128 -0
- package/dist/keys/credential-schemas.js.map +1 -0
- package/dist/keys/file-keystore.d.ts +130 -0
- package/dist/keys/file-keystore.d.ts.map +1 -0
- package/dist/keys/file-keystore.js +266 -0
- package/dist/keys/file-keystore.js.map +1 -0
- package/dist/keys/in-memory-keystore.d.ts +71 -0
- package/dist/keys/in-memory-keystore.d.ts.map +1 -0
- package/dist/keys/in-memory-keystore.js +85 -0
- package/dist/keys/in-memory-keystore.js.map +1 -0
- package/dist/keys/index.d.ts +14 -0
- package/dist/keys/index.d.ts.map +1 -0
- package/dist/keys/index.js +20 -0
- package/dist/keys/index.js.map +1 -0
- package/dist/keys/native-keystore.d.ts +111 -0
- package/dist/keys/native-keystore.d.ts.map +1 -0
- package/dist/keys/native-keystore.js +167 -0
- package/dist/keys/native-keystore.js.map +1 -0
- package/dist/keys/rotating-keystore.d.ts +207 -0
- package/dist/keys/rotating-keystore.d.ts.map +1 -0
- package/dist/keys/rotating-keystore.js +240 -0
- package/dist/keys/rotating-keystore.js.map +1 -0
- package/dist/sandbox/index.d.ts +6 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/sandbox.d.ts +55 -0
- package/dist/sandbox/sandbox.d.ts.map +1 -0
- package/dist/sandbox/sandbox.js +341 -0
- package/dist/sandbox/sandbox.js.map +1 -0
- package/dist/utils/amount.d.ts +76 -0
- package/dist/utils/amount.d.ts.map +1 -0
- package/dist/utils/amount.js +137 -0
- package/dist/utils/amount.js.map +1 -0
- package/dist/utils/gas.d.ts +69 -0
- package/dist/utils/gas.d.ts.map +1 -0
- package/dist/utils/gas.js +92 -0
- package/dist/utils/gas.js.map +1 -0
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +14 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/key.d.ts +117 -0
- package/dist/utils/key.d.ts.map +1 -0
- package/dist/utils/key.js +270 -0
- package/dist/utils/key.js.map +1 -0
- package/dist/utils/nep413.d.ts +97 -0
- package/dist/utils/nep413.d.ts.map +1 -0
- package/dist/utils/nep413.js +154 -0
- package/dist/utils/nep413.js.map +1 -0
- package/dist/utils/validation.d.ts +114 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +150 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/wallets/adapters.d.ts +119 -0
- package/dist/wallets/adapters.d.ts.map +1 -0
- package/dist/wallets/adapters.js +267 -0
- package/dist/wallets/adapters.js.map +1 -0
- package/dist/wallets/index.d.ts +11 -0
- package/dist/wallets/index.d.ts.map +1 -0
- package/dist/wallets/index.js +2 -0
- package/dist/wallets/index.js.map +1 -0
- package/dist/wallets/types.d.ts +99 -0
- package/dist/wallets/types.d.ts.map +1 -0
- package/dist/wallets/types.js +10 -0
- package/dist/wallets/types.js.map +1 -0
- package/package.json +78 -7
- package/index.js +0 -1
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
2
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
3
|
+
import { base58, base64 } from "@scure/base";
|
|
4
|
+
import { HDKey } from "@scure/bip32";
|
|
5
|
+
import * as bip39 from "@scure/bip39";
|
|
6
|
+
import { wordlist } from "@scure/bip39/wordlists/english.js";
|
|
7
|
+
import { ED25519_KEY_PREFIX, SECP256K1_KEY_PREFIX } from "../core/constants.js";
|
|
8
|
+
import { KeyType, } from "../core/types.js";
|
|
9
|
+
import { InvalidKeyError } from "../errors/index.js";
|
|
10
|
+
import { serializeNep413Message } from "./nep413.js";
|
|
11
|
+
/**
|
|
12
|
+
* Ed25519 key pair implementation.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* Implements the {@link KeyPair} interface used throughout the library and
|
|
16
|
+
* provides NEP-413 message signing via {@link Ed25519KeyPair.signNep413Message}.
|
|
17
|
+
*/
|
|
18
|
+
export class Ed25519KeyPair {
|
|
19
|
+
constructor(secretKey) {
|
|
20
|
+
// secretKey is 64 bytes: [32 bytes private key][32 bytes public key]
|
|
21
|
+
this.privateKey = secretKey.slice(0, 32);
|
|
22
|
+
const publicKeyData = secretKey.slice(32);
|
|
23
|
+
this.publicKey = {
|
|
24
|
+
keyType: KeyType.ED25519,
|
|
25
|
+
data: publicKeyData,
|
|
26
|
+
toString: () => ED25519_KEY_PREFIX + base58.encode(publicKeyData),
|
|
27
|
+
};
|
|
28
|
+
this.secretKey = ED25519_KEY_PREFIX + base58.encode(secretKey);
|
|
29
|
+
}
|
|
30
|
+
sign(message) {
|
|
31
|
+
const signature = ed25519.sign(message, this.privateKey);
|
|
32
|
+
return {
|
|
33
|
+
keyType: KeyType.ED25519,
|
|
34
|
+
data: signature,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sign a message according to NEP-413 specification
|
|
39
|
+
*
|
|
40
|
+
* NEP-413 enables off-chain message signing for authentication and ownership verification.
|
|
41
|
+
* The message is signed with a full-access key but does not require gas or blockchain state.
|
|
42
|
+
*
|
|
43
|
+
* @param accountId - The NEAR account ID that owns this key
|
|
44
|
+
* @param params - Message signing parameters (message, recipient, nonce)
|
|
45
|
+
* @returns Signed message with account ID, public key, and base64-encoded signature
|
|
46
|
+
*
|
|
47
|
+
* @see https://github.com/near/NEPs/blob/master/neps/nep-0413.md
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const nonce = crypto.getRandomValues(new Uint8Array(32))
|
|
52
|
+
* const signedMessage = keyPair.signNep413Message("alice.near", {
|
|
53
|
+
* message: "Login to MyApp",
|
|
54
|
+
* recipient: "myapp.near",
|
|
55
|
+
* nonce,
|
|
56
|
+
* })
|
|
57
|
+
* console.log(signedMessage.signature) // Base64-encoded signature
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
signNep413Message(accountId, params) {
|
|
61
|
+
// Serialize and hash the message according to NEP-413
|
|
62
|
+
const hash = serializeNep413Message(params);
|
|
63
|
+
// Sign the hash
|
|
64
|
+
const signature = ed25519.sign(hash, this.privateKey);
|
|
65
|
+
// Return signed message with base64-encoded signature
|
|
66
|
+
return {
|
|
67
|
+
accountId,
|
|
68
|
+
publicKey: this.publicKey.toString(),
|
|
69
|
+
signature: base64.encode(signature),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
static fromRandom() {
|
|
73
|
+
const privateKey = ed25519.utils.randomSecretKey();
|
|
74
|
+
const publicKey = ed25519.getPublicKey(privateKey);
|
|
75
|
+
// Combine into 64-byte format for compatibility
|
|
76
|
+
const secretKey = new Uint8Array(64);
|
|
77
|
+
secretKey.set(privateKey, 0);
|
|
78
|
+
secretKey.set(publicKey, 32);
|
|
79
|
+
return new Ed25519KeyPair(secretKey);
|
|
80
|
+
}
|
|
81
|
+
static fromString(keyString) {
|
|
82
|
+
const key = keyString.replace(ED25519_KEY_PREFIX, "");
|
|
83
|
+
const decoded = base58.decode(key);
|
|
84
|
+
return new Ed25519KeyPair(decoded);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Secp256k1 key pair implementation.
|
|
89
|
+
*
|
|
90
|
+
* NEAR expects secp256k1 public keys to be 64 bytes (uncompressed without 0x04 header).
|
|
91
|
+
* The secp256k1 library returns 65-byte uncompressed keys (with 0x04 header), so we
|
|
92
|
+
* manually remove/add that byte as needed.
|
|
93
|
+
*
|
|
94
|
+
* Signatures are 65 bytes: 64-byte signature + 1-byte recovery ID.
|
|
95
|
+
*/
|
|
96
|
+
export class Secp256k1KeyPair {
|
|
97
|
+
constructor(secretKey) {
|
|
98
|
+
// secretKey is 96 bytes: [32 bytes private key][64 bytes public key]
|
|
99
|
+
this.privateKey = secretKey.slice(0, 32);
|
|
100
|
+
const publicKeyData = secretKey.slice(32); // 64 bytes without 0x04 header
|
|
101
|
+
this.publicKey = {
|
|
102
|
+
keyType: KeyType.SECP256K1,
|
|
103
|
+
data: publicKeyData,
|
|
104
|
+
toString: () => SECP256K1_KEY_PREFIX + base58.encode(publicKeyData),
|
|
105
|
+
};
|
|
106
|
+
this.secretKey = SECP256K1_KEY_PREFIX + base58.encode(secretKey);
|
|
107
|
+
}
|
|
108
|
+
sign(message) {
|
|
109
|
+
// Sign with format: 'recovered' to get 65 bytes (recovery ID + signature)
|
|
110
|
+
// This is what NEAR expects: [recovery][r][s]
|
|
111
|
+
const signatureBytes = secp256k1.sign(message, this.privateKey, {
|
|
112
|
+
format: "recovered",
|
|
113
|
+
});
|
|
114
|
+
return {
|
|
115
|
+
keyType: KeyType.SECP256K1,
|
|
116
|
+
data: signatureBytes, // 65 bytes
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Sign a message according to NEP-413 specification
|
|
121
|
+
*
|
|
122
|
+
* NEP-413 enables off-chain message signing for authentication and ownership verification.
|
|
123
|
+
* The message is signed with a full-access key but does not require gas or blockchain state.
|
|
124
|
+
*
|
|
125
|
+
* @param accountId - The NEAR account ID that owns this key
|
|
126
|
+
* @param params - Message signing parameters (message, recipient, nonce)
|
|
127
|
+
* @returns Signed message with account ID, public key, and base64-encoded signature
|
|
128
|
+
*
|
|
129
|
+
* @see https://github.com/near/NEPs/blob/master/neps/nep-0413.md
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const nonce = crypto.getRandomValues(new Uint8Array(32))
|
|
134
|
+
* const signedMessage = keyPair.signNep413Message("alice.near", {
|
|
135
|
+
* message: "Login to MyApp",
|
|
136
|
+
* recipient: "myapp.near",
|
|
137
|
+
* nonce,
|
|
138
|
+
* })
|
|
139
|
+
* console.log(signedMessage.signature) // Base64-encoded signature
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
signNep413Message(accountId, params) {
|
|
143
|
+
// Serialize and hash the message according to NEP-413
|
|
144
|
+
const hash = serializeNep413Message(params);
|
|
145
|
+
// Sign the hash with format: 'recovered' for secp256k1
|
|
146
|
+
const signature = secp256k1.sign(hash, this.privateKey, {
|
|
147
|
+
format: "recovered",
|
|
148
|
+
});
|
|
149
|
+
// Return signed message with base64-encoded signature
|
|
150
|
+
return {
|
|
151
|
+
accountId,
|
|
152
|
+
publicKey: this.publicKey.toString(),
|
|
153
|
+
signature: base64.encode(signature),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
static fromRandom() {
|
|
157
|
+
// Generate random 32-byte private key
|
|
158
|
+
const privateKey = new Uint8Array(32);
|
|
159
|
+
crypto.getRandomValues(privateKey);
|
|
160
|
+
// Get uncompressed public key (65 bytes with 0x04 header)
|
|
161
|
+
const publicKeyFull = secp256k1.getPublicKey(privateKey, false);
|
|
162
|
+
// Remove 0x04 header to get 64 bytes for NEAR
|
|
163
|
+
const publicKey = publicKeyFull.slice(1);
|
|
164
|
+
// Combine into 96-byte format: 32 bytes private + 64 bytes public
|
|
165
|
+
const secretKey = new Uint8Array(96);
|
|
166
|
+
secretKey.set(privateKey, 0);
|
|
167
|
+
secretKey.set(publicKey, 32);
|
|
168
|
+
return new Secp256k1KeyPair(secretKey);
|
|
169
|
+
}
|
|
170
|
+
static fromString(keyString) {
|
|
171
|
+
const key = keyString.replace(SECP256K1_KEY_PREFIX, "");
|
|
172
|
+
const decoded = base58.decode(key);
|
|
173
|
+
return new Secp256k1KeyPair(decoded);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Generate a new random Ed25519 key pair.
|
|
178
|
+
* @returns A new {@link KeyPair} instance.
|
|
179
|
+
*/
|
|
180
|
+
export function generateKey() {
|
|
181
|
+
return Ed25519KeyPair.fromRandom();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Parse a key string to a {@link KeyPair}.
|
|
185
|
+
*
|
|
186
|
+
* @param keyString - Key string (e.g. `"ed25519:..."` or `"secp256k1:..."`).
|
|
187
|
+
* @returns A concrete {@link Ed25519KeyPair} or {@link Secp256k1KeyPair}.
|
|
188
|
+
*/
|
|
189
|
+
export function parseKey(keyString) {
|
|
190
|
+
if (keyString.startsWith(ED25519_KEY_PREFIX)) {
|
|
191
|
+
return Ed25519KeyPair.fromString(keyString);
|
|
192
|
+
}
|
|
193
|
+
if (keyString.startsWith(SECP256K1_KEY_PREFIX)) {
|
|
194
|
+
return Secp256k1KeyPair.fromString(keyString);
|
|
195
|
+
}
|
|
196
|
+
throw new InvalidKeyError(`Unsupported key type: ${keyString}`);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Parse a public key string to a {@link PublicKey} object.
|
|
200
|
+
*
|
|
201
|
+
* @param publicKeyString - Public key string (e.g. `"ed25519:..."` or `"secp256k1:..."`).
|
|
202
|
+
* @returns {@link PublicKey} instance.
|
|
203
|
+
*/
|
|
204
|
+
export function parsePublicKey(publicKeyString) {
|
|
205
|
+
if (publicKeyString.startsWith(ED25519_KEY_PREFIX)) {
|
|
206
|
+
const key = publicKeyString.replace(ED25519_KEY_PREFIX, "");
|
|
207
|
+
const decoded = base58.decode(key);
|
|
208
|
+
return {
|
|
209
|
+
keyType: KeyType.ED25519,
|
|
210
|
+
data: decoded,
|
|
211
|
+
toString: () => publicKeyString,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
if (publicKeyString.startsWith(SECP256K1_KEY_PREFIX)) {
|
|
215
|
+
const key = publicKeyString.replace(SECP256K1_KEY_PREFIX, "");
|
|
216
|
+
const decoded = base58.decode(key);
|
|
217
|
+
return {
|
|
218
|
+
keyType: KeyType.SECP256K1,
|
|
219
|
+
data: decoded,
|
|
220
|
+
toString: () => publicKeyString,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
throw new InvalidKeyError(`Unsupported public key type: ${publicKeyString}`);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Generate a BIP39 seed phrase (12 words by default)
|
|
227
|
+
* Uses proper BIP39 implementation with cryptographically secure randomness
|
|
228
|
+
* @param wordCount - Number of words (12, 15, 18, 21, or 24). Defaults to 12
|
|
229
|
+
* @returns A BIP39 seed phrase string
|
|
230
|
+
*/
|
|
231
|
+
export function generateSeedPhrase(wordCount = 12) {
|
|
232
|
+
// Map word count to entropy bits (as per BIP39 spec)
|
|
233
|
+
const entropyBits = wordCount * 11 - wordCount / 3;
|
|
234
|
+
const entropyBytes = entropyBits / 8;
|
|
235
|
+
// Generate cryptographically secure random entropy
|
|
236
|
+
const entropy = new Uint8Array(entropyBytes);
|
|
237
|
+
crypto.getRandomValues(entropy);
|
|
238
|
+
// Generate mnemonic from entropy
|
|
239
|
+
return bip39.entropyToMnemonic(entropy, wordlist);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Parse a BIP39 seed phrase to derive a key pair using proper BIP32/SLIP10 derivation
|
|
243
|
+
* @param phrase - BIP39 seed phrase (12-24 words)
|
|
244
|
+
* @param path - BIP32 derivation path (defaults to "m/44'/397'/0'" for NEAR)
|
|
245
|
+
* @returns KeyPair instance
|
|
246
|
+
*/
|
|
247
|
+
export function parseSeedPhrase(phrase, path = "m/44'/397'/0'") {
|
|
248
|
+
// Validate the mnemonic
|
|
249
|
+
if (!bip39.validateMnemonic(phrase, wordlist)) {
|
|
250
|
+
throw new InvalidKeyError("Invalid BIP39 seed phrase");
|
|
251
|
+
}
|
|
252
|
+
// Convert mnemonic to seed (64 bytes)
|
|
253
|
+
const seed = bip39.mnemonicToSeedSync(phrase);
|
|
254
|
+
// Derive HD key using BIP32 with ed25519 (SLIP10)
|
|
255
|
+
// Note: HDKey from @scure/bip32 supports ed25519 via SLIP10
|
|
256
|
+
const hdkey = HDKey.fromMasterSeed(seed);
|
|
257
|
+
const derived = hdkey.derive(path);
|
|
258
|
+
if (!derived.privateKey) {
|
|
259
|
+
throw new InvalidKeyError("Failed to derive private key from seed phrase");
|
|
260
|
+
}
|
|
261
|
+
// Get the ed25519 public key from private key
|
|
262
|
+
const privateKey = derived.privateKey;
|
|
263
|
+
const publicKey = ed25519.getPublicKey(privateKey);
|
|
264
|
+
// Combine into 64-byte format for compatibility
|
|
265
|
+
const secretKey = new Uint8Array(64);
|
|
266
|
+
secretKey.set(privateKey, 0);
|
|
267
|
+
secretKey.set(publicKey, 32);
|
|
268
|
+
return new Ed25519KeyPair(secretKey);
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key.js","sourceRoot":"","sources":["../../src/utils/key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAA;AACpC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAEL,OAAO,GAKR,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAEpD;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IAKzB,YAAY,SAAqB;QAC/B,qEAAqE;QACrE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACxC,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAEzC,IAAI,CAAC,SAAS,GAAG;YACf,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,aAAa;YACnB,QAAQ,EAAE,GAAG,EAAE,CAAC,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;SAClE,CAAA;QAED,IAAI,CAAC,SAAS,GAAG,kBAAkB,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAChE,CAAC;IAED,IAAI,CAAC,OAAmB;QACtB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;QACxD,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,SAAS;SAChB,CAAA;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,iBAAiB,CACf,SAAiB,EACjB,MAAyB;QAEzB,sDAAsD;QACtD,MAAM,IAAI,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAA;QAE3C,gBAAgB;QAChB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;QAErD,sDAAsD;QACtD,OAAO;YACL,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE;YACpC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;SACpC,CAAA;IACH,CAAC;IAED,MAAM,CAAC,UAAU;QACf,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,CAAA;QAClD,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;QAElD,gDAAgD;QAChD,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;QACpC,SAAS,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;QAC5B,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QAE5B,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC,CAAA;IACtC,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,SAAiB;QACjC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAA;QACrD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAClC,OAAO,IAAI,cAAc,CAAC,OAAO,CAAC,CAAA;IACpC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,gBAAgB;IAK3B,YAAY,SAAqB;QAC/B,qEAAqE;QACrE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;QACxC,MAAM,aAAa,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA,CAAC,+BAA+B;QAEzE,IAAI,CAAC,SAAS,GAAG;YACf,OAAO,EAAE,OAAO,CAAC,SAAS;YAC1B,IAAI,EAAE,aAAa;YACnB,QAAQ,EAAE,GAAG,EAAE,CAAC,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;SACpE,CAAA;QAED,IAAI,CAAC,SAAS,GAAG,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IAClE,CAAC;IAED,IAAI,CAAC,OAAmB;QACtB,0EAA0E;QAC1E,8CAA8C;QAC9C,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE;YAC9D,MAAM,EAAE,WAAW;SACpB,CAAC,CAAA;QAEF,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,SAAS;YAC1B,IAAI,EAAE,cAAc,EAAE,WAAW;SAClC,CAAA;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,iBAAiB,CACf,SAAiB,EACjB,MAAyB;QAEzB,sDAAsD;QACtD,MAAM,IAAI,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAA;QAE3C,uDAAuD;QACvD,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE;YACtD,MAAM,EAAE,WAAW;SACpB,CAAC,CAAA;QAEF,sDAAsD;QACtD,OAAO;YACL,SAAS;YACT,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE;YACpC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;SACpC,CAAA;IACH,CAAC;IAED,MAAM,CAAC,UAAU;QACf,sCAAsC;QACtC,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;QACrC,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;QAElC,0DAA0D;QAC1D,MAAM,aAAa,GAAG,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;QAE/D,8CAA8C;QAC9C,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAExC,kEAAkE;QAClE,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;QACpC,SAAS,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;QAC5B,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QAE5B,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACxC,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,SAAiB;QACjC,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAA;QACvD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAClC,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACtC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,cAAc,CAAC,UAAU,EAAE,CAAA;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,SAAiB;IACxC,IAAI,SAAS,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC7C,OAAO,cAAc,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,SAAS,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC/C,OAAO,gBAAgB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;IAC/C,CAAC;IAED,MAAM,IAAI,eAAe,CAAC,yBAAyB,SAAS,EAAE,CAAC,CAAA;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,eAAuB;IACpD,IAAI,eAAe,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAA;QAC3D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAClC,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,GAAG,EAAE,CAAC,eAAe;SAChC,CAAA;IACH,CAAC;IAED,IAAI,eAAe,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAA;QAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAClC,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,SAAS;YAC1B,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,GAAG,EAAE,CAAC,eAAe;SAChC,CAAA;IACH,CAAC;IAED,MAAM,IAAI,eAAe,CAAC,gCAAgC,eAAe,EAAE,CAAC,CAAA;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,YAAoC,EAAE;IAEtC,qDAAqD;IACrD,MAAM,WAAW,GAAG,SAAS,GAAG,EAAE,GAAG,SAAS,GAAG,CAAC,CAAA;IAClD,MAAM,YAAY,GAAG,WAAW,GAAG,CAAC,CAAA;IAEpC,mDAAmD;IACnD,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,CAAA;IAC5C,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IAE/B,iCAAiC;IACjC,OAAO,KAAK,CAAC,iBAAiB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,OAAe,eAAe;IAE9B,wBAAwB;IACxB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,eAAe,CAAC,2BAA2B,CAAC,CAAA;IACxD,CAAC;IAED,sCAAsC;IACtC,MAAM,IAAI,GAAG,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAE7C,kDAAkD;IAClD,4DAA4D;IAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAA;IACxC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAElC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAI,eAAe,CAAC,+CAA+C,CAAC,CAAA;IAC5E,CAAC;IAED,8CAA8C;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAA;IACrC,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;IAElD,gDAAgD;IAChD,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IACpC,SAAS,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;IAC5B,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IAE5B,OAAO,IAAI,cAAc,CAAC,SAAS,CAAC,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEP-413: Message signing utilities
|
|
3
|
+
*
|
|
4
|
+
* NEP-413 enables off-chain message signing for authentication and ownership verification
|
|
5
|
+
* without gas fees or blockchain transactions.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/near/NEPs/blob/master/neps/nep-0413.md
|
|
8
|
+
*/
|
|
9
|
+
import type { SignedMessage, SignMessageParams } from "../core/types.js";
|
|
10
|
+
/**
|
|
11
|
+
* NEP-413 tag prefix: 2^31 + 413 = 2147484061
|
|
12
|
+
*
|
|
13
|
+
* This prefix ensures that signed messages cannot be confused with valid transactions.
|
|
14
|
+
* The tag makes the message too long to be a valid signer account ID.
|
|
15
|
+
*/
|
|
16
|
+
export declare const NEP413_TAG = 2147484061;
|
|
17
|
+
/**
|
|
18
|
+
* NEP-413 message payload schema
|
|
19
|
+
*
|
|
20
|
+
* Fields are serialized in this order:
|
|
21
|
+
* 1. message: string - The message to sign
|
|
22
|
+
* 2. nonce: [u8; 32] - 32-byte nonce for replay protection
|
|
23
|
+
* 3. recipient: string - Recipient identifier (e.g., "alice.near" or "myapp.com")
|
|
24
|
+
* 4. callbackUrl: Option<string> - Optional callback URL for web wallets
|
|
25
|
+
*/
|
|
26
|
+
export declare const Nep413PayloadSchema: import("@zorsh/zorsh").Schema<{
|
|
27
|
+
message: string;
|
|
28
|
+
nonce: number[];
|
|
29
|
+
recipient: string;
|
|
30
|
+
callbackUrl: string | null;
|
|
31
|
+
}, string>;
|
|
32
|
+
/**
|
|
33
|
+
* Serialize NEP-413 message parameters for signing
|
|
34
|
+
*
|
|
35
|
+
* Serialization steps:
|
|
36
|
+
* 1. Serialize the tag (2147484061) as u32
|
|
37
|
+
* 2. Serialize the payload (message, nonce, recipient, callbackUrl)
|
|
38
|
+
* 3. Concatenate: tag_bytes + payload_bytes
|
|
39
|
+
* 4. Hash with SHA256
|
|
40
|
+
*
|
|
41
|
+
* @param params - Message signing parameters
|
|
42
|
+
* @returns Serialized and hashed message ready for signing
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* const nonce = crypto.getRandomValues(new Uint8Array(32))
|
|
47
|
+
* const hash = serializeNep413Message({
|
|
48
|
+
* message: "Login to MyApp",
|
|
49
|
+
* recipient: "myapp.near",
|
|
50
|
+
* nonce,
|
|
51
|
+
* })
|
|
52
|
+
* const signature = keyPair.sign(hash)
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function serializeNep413Message(params: SignMessageParams): Uint8Array;
|
|
56
|
+
/**
|
|
57
|
+
* Verify a NEP-413 signed message
|
|
58
|
+
*
|
|
59
|
+
* Verification steps:
|
|
60
|
+
* 1. Reconstruct the payload from parameters
|
|
61
|
+
* 2. Serialize and hash (tag + payload)
|
|
62
|
+
* 3. Verify the signature against the hash using the public key
|
|
63
|
+
*
|
|
64
|
+
* @param signedMessage - The signed message to verify
|
|
65
|
+
* @param params - Original message parameters (must match what was signed)
|
|
66
|
+
* @returns true if signature is valid, false otherwise
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const isValid = verifyNep413Signature(signedMessage, {
|
|
71
|
+
* message: "Login to MyApp",
|
|
72
|
+
* recipient: "myapp.near",
|
|
73
|
+
* nonce,
|
|
74
|
+
* })
|
|
75
|
+
* if (isValid) {
|
|
76
|
+
* console.log("Signature verified!")
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function verifyNep413Signature(signedMessage: SignedMessage, params: SignMessageParams): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Generate a random nonce for NEP-413 message signing
|
|
83
|
+
*
|
|
84
|
+
* @returns 32-byte random nonce
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```typescript
|
|
88
|
+
* const nonce = generateNep413Nonce()
|
|
89
|
+
* const signedMessage = await near.signMessage({
|
|
90
|
+
* message: "Login to MyApp",
|
|
91
|
+
* recipient: "myapp.near",
|
|
92
|
+
* nonce,
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function generateNep413Nonce(): Uint8Array;
|
|
97
|
+
//# sourceMappingURL=nep413.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nep413.d.ts","sourceRoot":"","sources":["../../src/utils/nep413.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAGxE;;;;;GAKG;AACH,eAAO,MAAM,UAAU,aAAa,CAAA;AAEpC;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB;;;;;UAK9B,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,UAAU,CAuB5E;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAiCT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CAEhD"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEP-413: Message signing utilities
|
|
3
|
+
*
|
|
4
|
+
* NEP-413 enables off-chain message signing for authentication and ownership verification
|
|
5
|
+
* without gas fees or blockchain transactions.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/near/NEPs/blob/master/neps/nep-0413.md
|
|
8
|
+
*/
|
|
9
|
+
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
10
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
11
|
+
import { base58, base64 } from "@scure/base";
|
|
12
|
+
import { b } from "@zorsh/zorsh";
|
|
13
|
+
import { parsePublicKey } from "./key.js";
|
|
14
|
+
/**
|
|
15
|
+
* NEP-413 tag prefix: 2^31 + 413 = 2147484061
|
|
16
|
+
*
|
|
17
|
+
* This prefix ensures that signed messages cannot be confused with valid transactions.
|
|
18
|
+
* The tag makes the message too long to be a valid signer account ID.
|
|
19
|
+
*/
|
|
20
|
+
export const NEP413_TAG = 2147484061;
|
|
21
|
+
/**
|
|
22
|
+
* NEP-413 message payload schema
|
|
23
|
+
*
|
|
24
|
+
* Fields are serialized in this order:
|
|
25
|
+
* 1. message: string - The message to sign
|
|
26
|
+
* 2. nonce: [u8; 32] - 32-byte nonce for replay protection
|
|
27
|
+
* 3. recipient: string - Recipient identifier (e.g., "alice.near" or "myapp.com")
|
|
28
|
+
* 4. callbackUrl: Option<string> - Optional callback URL for web wallets
|
|
29
|
+
*/
|
|
30
|
+
export const Nep413PayloadSchema = b.struct({
|
|
31
|
+
message: b.string(),
|
|
32
|
+
nonce: b.array(b.u8(), 32),
|
|
33
|
+
recipient: b.string(),
|
|
34
|
+
callbackUrl: b.option(b.string()),
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Serialize NEP-413 message parameters for signing
|
|
38
|
+
*
|
|
39
|
+
* Serialization steps:
|
|
40
|
+
* 1. Serialize the tag (2147484061) as u32
|
|
41
|
+
* 2. Serialize the payload (message, nonce, recipient, callbackUrl)
|
|
42
|
+
* 3. Concatenate: tag_bytes + payload_bytes
|
|
43
|
+
* 4. Hash with SHA256
|
|
44
|
+
*
|
|
45
|
+
* @param params - Message signing parameters
|
|
46
|
+
* @returns Serialized and hashed message ready for signing
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const nonce = crypto.getRandomValues(new Uint8Array(32))
|
|
51
|
+
* const hash = serializeNep413Message({
|
|
52
|
+
* message: "Login to MyApp",
|
|
53
|
+
* recipient: "myapp.near",
|
|
54
|
+
* nonce,
|
|
55
|
+
* })
|
|
56
|
+
* const signature = keyPair.sign(hash)
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function serializeNep413Message(params) {
|
|
60
|
+
if (params.nonce.length !== 32) {
|
|
61
|
+
throw new Error("Nonce must be exactly 32 bytes");
|
|
62
|
+
}
|
|
63
|
+
// Serialize tag as u32
|
|
64
|
+
const tagBytes = b.u32().serialize(NEP413_TAG);
|
|
65
|
+
// Serialize payload
|
|
66
|
+
const payloadBytes = Nep413PayloadSchema.serialize({
|
|
67
|
+
message: params.message,
|
|
68
|
+
nonce: Array.from(params.nonce),
|
|
69
|
+
recipient: params.recipient,
|
|
70
|
+
callbackUrl: null, // Optional, not typically used in direct signing
|
|
71
|
+
});
|
|
72
|
+
// Concatenate tag + payload
|
|
73
|
+
const combined = new Uint8Array(tagBytes.length + payloadBytes.length);
|
|
74
|
+
combined.set(tagBytes, 0);
|
|
75
|
+
combined.set(payloadBytes, tagBytes.length);
|
|
76
|
+
// Hash the combined bytes
|
|
77
|
+
return sha256(combined);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Verify a NEP-413 signed message
|
|
81
|
+
*
|
|
82
|
+
* Verification steps:
|
|
83
|
+
* 1. Reconstruct the payload from parameters
|
|
84
|
+
* 2. Serialize and hash (tag + payload)
|
|
85
|
+
* 3. Verify the signature against the hash using the public key
|
|
86
|
+
*
|
|
87
|
+
* @param signedMessage - The signed message to verify
|
|
88
|
+
* @param params - Original message parameters (must match what was signed)
|
|
89
|
+
* @returns true if signature is valid, false otherwise
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* const isValid = verifyNep413Signature(signedMessage, {
|
|
94
|
+
* message: "Login to MyApp",
|
|
95
|
+
* recipient: "myapp.near",
|
|
96
|
+
* nonce,
|
|
97
|
+
* })
|
|
98
|
+
* if (isValid) {
|
|
99
|
+
* console.log("Signature verified!")
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export function verifyNep413Signature(signedMessage, params) {
|
|
104
|
+
try {
|
|
105
|
+
// Parse the public key
|
|
106
|
+
const publicKey = parsePublicKey(signedMessage.publicKey);
|
|
107
|
+
// Only Ed25519 is currently supported
|
|
108
|
+
if (publicKey.keyType !== 0) {
|
|
109
|
+
throw new Error("Only Ed25519 keys are supported for NEP-413");
|
|
110
|
+
}
|
|
111
|
+
// Reconstruct the hashed payload
|
|
112
|
+
const hash = serializeNep413Message(params);
|
|
113
|
+
// Decode the signature
|
|
114
|
+
// Try base64 first (most common), fallback to base58
|
|
115
|
+
let signatureBytes;
|
|
116
|
+
try {
|
|
117
|
+
signatureBytes = base64.decode(signedMessage.signature);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
try {
|
|
121
|
+
// Remove ed25519: prefix if present
|
|
122
|
+
const sig = signedMessage.signature.replace("ed25519:", "");
|
|
123
|
+
signatureBytes = base58.decode(sig);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Verify the signature
|
|
130
|
+
return ed25519.verify(signatureBytes, hash, publicKey.data);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Generate a random nonce for NEP-413 message signing
|
|
138
|
+
*
|
|
139
|
+
* @returns 32-byte random nonce
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const nonce = generateNep413Nonce()
|
|
144
|
+
* const signedMessage = await near.signMessage({
|
|
145
|
+
* message: "Login to MyApp",
|
|
146
|
+
* recipient: "myapp.near",
|
|
147
|
+
* nonce,
|
|
148
|
+
* })
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
151
|
+
export function generateNep413Nonce() {
|
|
152
|
+
return crypto.getRandomValues(new Uint8Array(32));
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=nep413.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nep413.js","sourceRoot":"","sources":["../../src/utils/nep413.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,cAAc,CAAA;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAA;AAEpC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC;IAC1B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CAClC,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAyB;IAC9D,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IAED,uBAAuB;IACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;IAE9C,oBAAoB;IACpB,MAAM,YAAY,GAAG,mBAAmB,CAAC,SAAS,CAAC;QACjD,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,IAAI,EAAE,iDAAiD;KACrE,CAAC,CAAA;IAEF,4BAA4B;IAC5B,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAA;IACtE,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAA;IACzB,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;IAE3C,0BAA0B;IAC1B,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AACzB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,qBAAqB,CACnC,aAA4B,EAC5B,MAAyB;IAEzB,IAAI,CAAC;QACH,uBAAuB;QACvB,MAAM,SAAS,GAAG,cAAc,CAAC,aAAa,CAAC,SAAS,CAAC,CAAA;QAEzD,sCAAsC;QACtC,IAAI,SAAS,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;QAChE,CAAC;QAED,iCAAiC;QACjC,MAAM,IAAI,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAA;QAE3C,uBAAuB;QACvB,qDAAqD;QACrD,IAAI,cAA0B,CAAA;QAC9B,IAAI,CAAC;YACH,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAA;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC;gBACH,oCAAoC;gBACpC,MAAM,GAAG,GAAG,aAAa,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;gBAC3D,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACrC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,OAAO,OAAO,CAAC,MAAM,CAAC,cAAc,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAA;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;AACnD,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod validation schemas and helpers for NEAR types.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* These schemas power runtime validation for account IDs, public/private keys,
|
|
6
|
+
* amounts, and gas while keeping the developer-facing API ergonomic via
|
|
7
|
+
* helpers like {@link validateAccountId} and {@link normalizeAmount}.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
/**
|
|
11
|
+
* Schema for validating NEAR account IDs.
|
|
12
|
+
*
|
|
13
|
+
* Rules:
|
|
14
|
+
* - Length: 2-64 characters
|
|
15
|
+
* - Characters: lowercase alphanumeric, hyphens, underscores, and dots
|
|
16
|
+
* - Pattern: subdomain-like structure (e.g., alice.near, contract.mainnet)
|
|
17
|
+
*/
|
|
18
|
+
export declare const AccountIdSchema: z.ZodString;
|
|
19
|
+
export type AccountId = z.infer<typeof AccountIdSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Schema for validating NEAR public keys.
|
|
22
|
+
*
|
|
23
|
+
* Supports:
|
|
24
|
+
* - Ed25519: "ed25519:..." (base58 encoded)
|
|
25
|
+
* - Secp256k1: "secp256k1:..." (base58 encoded)
|
|
26
|
+
*/
|
|
27
|
+
export declare const PublicKeySchema: z.ZodString;
|
|
28
|
+
export type PublicKeyString = z.infer<typeof PublicKeySchema>;
|
|
29
|
+
/**
|
|
30
|
+
* Type-safe private key string using template literal types.
|
|
31
|
+
*
|
|
32
|
+
* Provides compile-time type safety for private keys.
|
|
33
|
+
* Supports both ed25519 and secp256k1 keys.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const key: PrivateKey = 'ed25519:...' // ✅ Valid
|
|
38
|
+
* const key: PrivateKey = 'secp256k1:...' // ✅ Valid
|
|
39
|
+
* const key: PrivateKey = 'alice.near' // ❌ Type error at compile time
|
|
40
|
+
*
|
|
41
|
+
* // Function signature ensures type safety
|
|
42
|
+
* function signWith(key: PrivateKey) { ... }
|
|
43
|
+
* signWith('ed25519:abc') // ✅ Valid
|
|
44
|
+
* signWith('secp256k1:abc') // ✅ Valid
|
|
45
|
+
* signWith('alice.near') // ❌ Type error
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export type PrivateKey = `ed25519:${string}` | `secp256k1:${string}`;
|
|
49
|
+
/**
|
|
50
|
+
* Schema for validating NEAR private keys.
|
|
51
|
+
*
|
|
52
|
+
* Supports:
|
|
53
|
+
* - Ed25519: "ed25519:..." (base58 encoded, 64 bytes)
|
|
54
|
+
* - Secp256k1: "secp256k1:..." (base58 encoded, 96 bytes)
|
|
55
|
+
*/
|
|
56
|
+
export declare const PrivateKeySchema: z.ZodString;
|
|
57
|
+
export type PrivateKeyString = z.infer<typeof PrivateKeySchema>;
|
|
58
|
+
/**
|
|
59
|
+
* Schema for NEAR amounts with explicit units.
|
|
60
|
+
*
|
|
61
|
+
* Accepts:
|
|
62
|
+
* - String with unit: "10 NEAR", "1000000 yocto"
|
|
63
|
+
* - Created via Amount.NEAR(10) or Amount.yocto(1000000n)
|
|
64
|
+
* - Raw bigint: 1000000n (treated as yoctoNEAR)
|
|
65
|
+
*
|
|
66
|
+
* Rejects bare numbers to prevent unit confusion.
|
|
67
|
+
* Normalizes to yoctoNEAR string.
|
|
68
|
+
*/
|
|
69
|
+
export declare const AmountSchema: z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodBigInt]>, z.ZodTransform<string, string | bigint>>;
|
|
70
|
+
export type Amount = z.input<typeof AmountSchema>;
|
|
71
|
+
/**
|
|
72
|
+
* Schema for gas amounts.
|
|
73
|
+
*
|
|
74
|
+
* Accepts:
|
|
75
|
+
* - String with unit: "30 Tgas", Gas.Tgas(30)
|
|
76
|
+
* - Raw gas number strings for advanced use
|
|
77
|
+
*
|
|
78
|
+
* Normalizes to raw gas string.
|
|
79
|
+
*/
|
|
80
|
+
export declare const GasSchema: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
81
|
+
export type Gas = z.input<typeof GasSchema>;
|
|
82
|
+
/**
|
|
83
|
+
* Validate account ID (throws on invalid).
|
|
84
|
+
*/
|
|
85
|
+
export declare function validateAccountId(accountId: string): string;
|
|
86
|
+
/**
|
|
87
|
+
* Check if account ID is valid (boolean).
|
|
88
|
+
*/
|
|
89
|
+
export declare function isValidAccountId(accountId: string): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Validate public key (throws on invalid).
|
|
92
|
+
*/
|
|
93
|
+
export declare function validatePublicKey(key: string): string;
|
|
94
|
+
/**
|
|
95
|
+
* Check if public key is valid (boolean).
|
|
96
|
+
*/
|
|
97
|
+
export declare function isValidPublicKey(key: string): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Validate private key (throws on invalid).
|
|
100
|
+
*/
|
|
101
|
+
export declare function validatePrivateKey(key: string): string;
|
|
102
|
+
/**
|
|
103
|
+
* Check if private key is valid (boolean).
|
|
104
|
+
*/
|
|
105
|
+
export declare function isPrivateKey(key: string): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Normalize amount to yoctoNEAR string.
|
|
108
|
+
*/
|
|
109
|
+
export declare function normalizeAmount(amount: Amount): string;
|
|
110
|
+
/**
|
|
111
|
+
* Normalize gas to gas string.
|
|
112
|
+
*/
|
|
113
|
+
export declare function normalizeGas(gas: Gas): string;
|
|
114
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAyBvB;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,aAazB,CAAA;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAIvD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,aAaoB,CAAA;AAEhD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAI7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,MAAM,EAAE,GAAG,aAAa,MAAM,EAAE,CAAA;AAEpE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,aAaoB,CAAA;AAEjD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AAI/D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,qGAIrB,CAAA;AAEJ,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAIjD;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,wDAEpB,CAAA;AAEF,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA;AAI3C;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAE7C"}
|