@actioncodes/protocol 1.0.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 +201 -0
- package/README.md +55 -0
- package/dist/actioncode.d.ts +114 -0
- package/dist/actioncode.d.ts.map +1 -0
- package/dist/actioncode.js +159 -0
- package/dist/adapters/base.d.ts +52 -0
- package/dist/adapters/base.d.ts.map +1 -0
- package/dist/adapters/base.js +41 -0
- package/dist/adapters/solana/index.d.ts +2 -0
- package/dist/adapters/solana/index.d.ts.map +1 -0
- package/dist/adapters/solana/index.js +17 -0
- package/dist/adapters/solana/solana.d.ts +84 -0
- package/dist/adapters/solana/solana.d.ts.map +1 -0
- package/dist/adapters/solana/solana.js +223 -0
- package/dist/codegen.d.ts +73 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +118 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +11 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/meta.d.ts +54 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +91 -0
- package/dist/protocol.d.ts +167 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +280 -0
- package/docs/README.md +59 -0
- package/docs/_media/LICENSE +201 -0
- package/docs/_media/README.md +28 -0
- package/docs/actioncode/README.md +21 -0
- package/docs/actioncode/classes/ActionCode.md +412 -0
- package/docs/actioncode/interfaces/ActionCodeFields.md +95 -0
- package/docs/actioncode/interfaces/ActionCodeMetadata.md +25 -0
- package/docs/actioncode/interfaces/ActionCodeTransaction.md +39 -0
- package/docs/actioncode/type-aliases/ActionCodeStatus.md +11 -0
- package/docs/adapters/base/README.md +11 -0
- package/docs/adapters/base/classes/BaseChainAdapter.md +222 -0
- package/docs/adapters/solana/README.md +19 -0
- package/docs/adapters/solana/solana/README.md +15 -0
- package/docs/adapters/solana/solana/classes/SolanaAdapter.md +306 -0
- package/docs/adapters/solana/solana/type-aliases/SolanaTransaction.md +13 -0
- package/docs/codegen/README.md +11 -0
- package/docs/codegen/classes/CodeGenerator.md +337 -0
- package/docs/constants/README.md +22 -0
- package/docs/constants/type-aliases/SupportedChain.md +11 -0
- package/docs/constants/variables/CODE_LENGTH.md +11 -0
- package/docs/constants/variables/CODE_TTL.md +11 -0
- package/docs/constants/variables/MAX_PREFIX_LENGTH.md +11 -0
- package/docs/constants/variables/MIN_PREFIX_LENGTH.md +11 -0
- package/docs/constants/variables/PROTOCOL_CODE_PREFIX.md +11 -0
- package/docs/constants/variables/PROTOCOL_PREFIX.md +11 -0
- package/docs/constants/variables/PROTOCOL_VERSION.md +11 -0
- package/docs/constants/variables/SUPPORTED_CHAINS.md +11 -0
- package/docs/index/README.md +139 -0
- package/docs/meta/README.md +15 -0
- package/docs/meta/classes/ProtocolMetaParser.md +177 -0
- package/docs/meta/interfaces/ProtocolMetaV1.md +59 -0
- package/docs/modules.md +17 -0
- package/docs/protocol/README.md +51 -0
- package/docs/protocol/classes/ActionCodesProtocol.md +616 -0
- package/docs/protocol/interfaces/ProtocolConfig.md +71 -0
- package/package.json +90 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
import { Transaction, TransactionInstruction, VersionedTransaction } from '@solana/web3.js';
|
2
|
+
import { ProtocolMetaV1 } from '../../meta';
|
3
|
+
import { BaseChainAdapter } from '../base';
|
4
|
+
/**
|
5
|
+
* Solana transaction type union
|
6
|
+
*/
|
7
|
+
export type SolanaTransaction = Transaction | VersionedTransaction;
|
8
|
+
/**
|
9
|
+
* Simple Solana adapter for protocol meta operations
|
10
|
+
* Supports both legacy and versioned transactions
|
11
|
+
*/
|
12
|
+
export declare class SolanaAdapter extends BaseChainAdapter<SolanaTransaction> {
|
13
|
+
private static readonly MEMO_PROGRAM_ID;
|
14
|
+
readonly chain = "solana";
|
15
|
+
/**
|
16
|
+
* Encode protocol meta as a Solana memo instruction
|
17
|
+
* @param meta - The protocol meta to encode
|
18
|
+
* @returns TransactionInstruction for the memo
|
19
|
+
*/
|
20
|
+
encode(meta: ProtocolMetaV1): TransactionInstruction;
|
21
|
+
/**
|
22
|
+
* Decode protocol meta from Solana transaction (legacy or versioned)
|
23
|
+
* @param tx - The Solana transaction
|
24
|
+
* @returns Decoded ProtocolMetaV1 or null if not found
|
25
|
+
*/
|
26
|
+
decode(tx: SolanaTransaction): ProtocolMetaV1 | null;
|
27
|
+
/**
|
28
|
+
* Validate transaction with protocol meta and authority list
|
29
|
+
* @param tx - The Solana transaction
|
30
|
+
* @param authorities - Array of valid protocol authority public keys (base58)
|
31
|
+
* @param expectedPrefix - Expected protocol prefix (default: 'DEFAULT')
|
32
|
+
* @returns True if transaction is valid
|
33
|
+
*/
|
34
|
+
validate(tx: SolanaTransaction, authorities: string[], expectedPrefix?: string): boolean;
|
35
|
+
/**
|
36
|
+
* Check if the issuer has signed the transaction
|
37
|
+
* @param tx - The Solana transaction
|
38
|
+
* @param issuer - Issuer public key to check
|
39
|
+
* @returns True if issuer has signed
|
40
|
+
*/
|
41
|
+
hasIssuerSignature(tx: SolanaTransaction, issuer: string): boolean;
|
42
|
+
/**
|
43
|
+
* Decode protocol meta from legacy Solana transaction
|
44
|
+
*/
|
45
|
+
private decodeLegacyTransaction;
|
46
|
+
/**
|
47
|
+
* Decode protocol meta from versioned Solana transaction
|
48
|
+
*/
|
49
|
+
private decodeVersionedTransaction;
|
50
|
+
/**
|
51
|
+
* Decode protocol meta from MessageV0
|
52
|
+
*/
|
53
|
+
private decodeMessageV0;
|
54
|
+
/**
|
55
|
+
* Check if the issuer has signed a legacy transaction
|
56
|
+
*/
|
57
|
+
private hasIssuerSignatureLegacy;
|
58
|
+
/**
|
59
|
+
* Check if the issuer has signed a versioned transaction
|
60
|
+
*/
|
61
|
+
private hasIssuerSignatureVersioned;
|
62
|
+
/**
|
63
|
+
* Validate Solana transaction integrity with additional checks
|
64
|
+
* @param tx - The Solana transaction
|
65
|
+
* @param meta - Decoded protocol meta
|
66
|
+
* @returns True if transaction integrity is valid
|
67
|
+
*/
|
68
|
+
protected validateTransactionIntegrity(tx: SolanaTransaction, meta: ProtocolMetaV1): boolean;
|
69
|
+
/**
|
70
|
+
* Decode protocol meta from base64 string (for backward compatibility)
|
71
|
+
* @param base64String - Base64 encoded transaction
|
72
|
+
* @returns Decoded ProtocolMetaV1 or null
|
73
|
+
*/
|
74
|
+
decodeFromBase64(base64String: string): ProtocolMetaV1 | null;
|
75
|
+
/**
|
76
|
+
* Validate base64 transaction (for backward compatibility)
|
77
|
+
* @param base64String - Base64 encoded transaction
|
78
|
+
* @param authorities - Array of valid protocol authority public keys (base58)
|
79
|
+
* @param expectedPrefix - Expected protocol prefix (default: 'DEFAULT')
|
80
|
+
* @returns True if transaction is valid
|
81
|
+
*/
|
82
|
+
validateFromBase64(base64String: string, authorities: string[], expectedPrefix?: string): boolean;
|
83
|
+
}
|
84
|
+
//# sourceMappingURL=solana.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"solana.d.ts","sourceRoot":"","sources":["../../../src/adapters/solana/solana.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EAEvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,cAAc,EAAsB,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEnE;;;GAGG;AACH,qBAAa,aAAc,SAAQ,gBAAgB,CAAC,iBAAiB,CAAC;IAClE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAmB;IAE1D,QAAQ,CAAC,KAAK,YAAY;IAE1B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,sBAAsB;IAKpD;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,iBAAiB,GAAG,cAAc,GAAG,IAAI;IAWpD;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,cAAc,GAAE,MAAkB,GAAG,OAAO;IAInG;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO;IAWlE;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAqB/B;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAUlC;;OAEG;IACH,OAAO,CAAC,eAAe;IAuBvB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAMhC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAenC;;;;;OAKG;IACH,SAAS,CAAC,4BAA4B,CAAC,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO;IAqB5F;;;;OAIG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAgB7D;;;;;;OAMG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,cAAc,GAAE,MAAkB,GAAG,OAAO;CAe/G"}
|
@@ -0,0 +1,223 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.SolanaAdapter = void 0;
|
4
|
+
const web3_js_1 = require("@solana/web3.js");
|
5
|
+
const spl_memo_1 = require("@solana/spl-memo");
|
6
|
+
const meta_1 = require("../../meta");
|
7
|
+
const base_1 = require("../base");
|
8
|
+
/**
|
9
|
+
* Simple Solana adapter for protocol meta operations
|
10
|
+
* Supports both legacy and versioned transactions
|
11
|
+
*/
|
12
|
+
class SolanaAdapter extends base_1.BaseChainAdapter {
|
13
|
+
constructor() {
|
14
|
+
super(...arguments);
|
15
|
+
this.chain = 'solana';
|
16
|
+
}
|
17
|
+
/**
|
18
|
+
* Encode protocol meta as a Solana memo instruction
|
19
|
+
* @param meta - The protocol meta to encode
|
20
|
+
* @returns TransactionInstruction for the memo
|
21
|
+
*/
|
22
|
+
encode(meta) {
|
23
|
+
const metaString = meta_1.ProtocolMetaParser.serialize(meta);
|
24
|
+
return (0, spl_memo_1.createMemoInstruction)(metaString);
|
25
|
+
}
|
26
|
+
/**
|
27
|
+
* Decode protocol meta from Solana transaction (legacy or versioned)
|
28
|
+
* @param tx - The Solana transaction
|
29
|
+
* @returns Decoded ProtocolMetaV1 or null if not found
|
30
|
+
*/
|
31
|
+
decode(tx) {
|
32
|
+
// Check if it's a versioned transaction
|
33
|
+
if ('message' in tx && tx.message) {
|
34
|
+
return this.decodeVersionedTransaction(tx);
|
35
|
+
}
|
36
|
+
else if ('instructions' in tx && Array.isArray(tx.instructions)) {
|
37
|
+
return this.decodeLegacyTransaction(tx);
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
return null;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Validate transaction with protocol meta and authority list
|
45
|
+
* @param tx - The Solana transaction
|
46
|
+
* @param authorities - Array of valid protocol authority public keys (base58)
|
47
|
+
* @param expectedPrefix - Expected protocol prefix (default: 'DEFAULT')
|
48
|
+
* @returns True if transaction is valid
|
49
|
+
*/
|
50
|
+
validate(tx, authorities, expectedPrefix = 'DEFAULT') {
|
51
|
+
return this.detectTampering(tx, authorities, expectedPrefix);
|
52
|
+
}
|
53
|
+
/**
|
54
|
+
* Check if the issuer has signed the transaction
|
55
|
+
* @param tx - The Solana transaction
|
56
|
+
* @param issuer - Issuer public key to check
|
57
|
+
* @returns True if issuer has signed
|
58
|
+
*/
|
59
|
+
hasIssuerSignature(tx, issuer) {
|
60
|
+
// Check if it's a versioned transaction
|
61
|
+
if ('message' in tx && tx.message) {
|
62
|
+
return this.hasIssuerSignatureVersioned(tx, issuer);
|
63
|
+
}
|
64
|
+
else if ('signatures' in tx && Array.isArray(tx.signatures)) {
|
65
|
+
return this.hasIssuerSignatureLegacy(tx, issuer);
|
66
|
+
}
|
67
|
+
else {
|
68
|
+
return false;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
/**
|
72
|
+
* Decode protocol meta from legacy Solana transaction
|
73
|
+
*/
|
74
|
+
decodeLegacyTransaction(transaction) {
|
75
|
+
for (const instruction of transaction.instructions) {
|
76
|
+
if (instruction.programId.equals(SolanaAdapter.MEMO_PROGRAM_ID)) {
|
77
|
+
const memoData = instruction.data;
|
78
|
+
if (memoData && memoData.length > 0) {
|
79
|
+
try {
|
80
|
+
const memoString = new TextDecoder().decode(memoData);
|
81
|
+
const meta = meta_1.ProtocolMetaParser.parse(memoString);
|
82
|
+
if (meta && meta.version !== '1') {
|
83
|
+
return null;
|
84
|
+
}
|
85
|
+
return meta;
|
86
|
+
}
|
87
|
+
catch {
|
88
|
+
return null;
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
93
|
+
return null;
|
94
|
+
}
|
95
|
+
/**
|
96
|
+
* Decode protocol meta from versioned Solana transaction
|
97
|
+
*/
|
98
|
+
decodeVersionedTransaction(transaction) {
|
99
|
+
const message = transaction.message;
|
100
|
+
if (message instanceof web3_js_1.MessageV0) {
|
101
|
+
return this.decodeMessageV0(message);
|
102
|
+
}
|
103
|
+
else {
|
104
|
+
return null;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
/**
|
108
|
+
* Decode protocol meta from MessageV0
|
109
|
+
*/
|
110
|
+
decodeMessageV0(message) {
|
111
|
+
for (const instruction of message.compiledInstructions) {
|
112
|
+
const programId = message.staticAccountKeys[instruction.programIdIndex];
|
113
|
+
if (programId.equals(SolanaAdapter.MEMO_PROGRAM_ID)) {
|
114
|
+
const memoData = instruction.data;
|
115
|
+
if (memoData && memoData.length > 0) {
|
116
|
+
try {
|
117
|
+
const memoString = new TextDecoder().decode(memoData);
|
118
|
+
const meta = meta_1.ProtocolMetaParser.parse(memoString);
|
119
|
+
if (meta && meta.version !== '1') {
|
120
|
+
return null;
|
121
|
+
}
|
122
|
+
return meta;
|
123
|
+
}
|
124
|
+
catch {
|
125
|
+
return null;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
}
|
129
|
+
}
|
130
|
+
return null;
|
131
|
+
}
|
132
|
+
/**
|
133
|
+
* Check if the issuer has signed a legacy transaction
|
134
|
+
*/
|
135
|
+
hasIssuerSignatureLegacy(transaction, issuer) {
|
136
|
+
return transaction.signatures.some(sig => sig.publicKey.toBase58() === issuer);
|
137
|
+
}
|
138
|
+
/**
|
139
|
+
* Check if the issuer has signed a versioned transaction
|
140
|
+
*/
|
141
|
+
hasIssuerSignatureVersioned(transaction, issuer) {
|
142
|
+
const message = transaction.message;
|
143
|
+
if (message instanceof web3_js_1.MessageV0) {
|
144
|
+
// Check static account keys
|
145
|
+
for (const key of message.staticAccountKeys) {
|
146
|
+
if (key.toBase58() === issuer) {
|
147
|
+
return true;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
return false;
|
152
|
+
}
|
153
|
+
/**
|
154
|
+
* Validate Solana transaction integrity with additional checks
|
155
|
+
* @param tx - The Solana transaction
|
156
|
+
* @param meta - Decoded protocol meta
|
157
|
+
* @returns True if transaction integrity is valid
|
158
|
+
*/
|
159
|
+
validateTransactionIntegrity(tx, meta) {
|
160
|
+
// Additional Solana-specific validation can be added here
|
161
|
+
// For example, checking transaction signatures, recent blockhash, etc.
|
162
|
+
// Verify that the memo instruction contains the expected protocol meta
|
163
|
+
const decodedMeta = this.decode(tx);
|
164
|
+
if (!decodedMeta) {
|
165
|
+
return false;
|
166
|
+
}
|
167
|
+
// Cross-check the decoded meta with the provided meta
|
168
|
+
return (decodedMeta.version === meta.version &&
|
169
|
+
decodedMeta.prefix === meta.prefix &&
|
170
|
+
decodedMeta.initiator === meta.initiator &&
|
171
|
+
decodedMeta.id === meta.id &&
|
172
|
+
decodedMeta.iss === meta.iss &&
|
173
|
+
decodedMeta.params === meta.params);
|
174
|
+
}
|
175
|
+
/**
|
176
|
+
* Decode protocol meta from base64 string (for backward compatibility)
|
177
|
+
* @param base64String - Base64 encoded transaction
|
178
|
+
* @returns Decoded ProtocolMetaV1 or null
|
179
|
+
*/
|
180
|
+
decodeFromBase64(base64String) {
|
181
|
+
try {
|
182
|
+
const buffer = Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
|
183
|
+
// Try legacy first, then versioned
|
184
|
+
try {
|
185
|
+
const transaction = web3_js_1.Transaction.from(buffer);
|
186
|
+
return this.decode(transaction);
|
187
|
+
}
|
188
|
+
catch {
|
189
|
+
const transaction = web3_js_1.VersionedTransaction.deserialize(buffer);
|
190
|
+
return this.decode(transaction);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
catch {
|
194
|
+
return null;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
/**
|
198
|
+
* Validate base64 transaction (for backward compatibility)
|
199
|
+
* @param base64String - Base64 encoded transaction
|
200
|
+
* @param authorities - Array of valid protocol authority public keys (base58)
|
201
|
+
* @param expectedPrefix - Expected protocol prefix (default: 'DEFAULT')
|
202
|
+
* @returns True if transaction is valid
|
203
|
+
*/
|
204
|
+
validateFromBase64(base64String, authorities, expectedPrefix = 'DEFAULT') {
|
205
|
+
try {
|
206
|
+
const buffer = Uint8Array.from(atob(base64String), c => c.charCodeAt(0));
|
207
|
+
// Try legacy first, then versioned
|
208
|
+
try {
|
209
|
+
const transaction = web3_js_1.Transaction.from(buffer);
|
210
|
+
return this.validate(transaction, authorities, expectedPrefix);
|
211
|
+
}
|
212
|
+
catch {
|
213
|
+
const transaction = web3_js_1.VersionedTransaction.deserialize(buffer);
|
214
|
+
return this.validate(transaction, authorities, expectedPrefix);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
catch {
|
218
|
+
return false;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
exports.SolanaAdapter = SolanaAdapter;
|
223
|
+
SolanaAdapter.MEMO_PROGRAM_ID = spl_memo_1.MEMO_PROGRAM_ID;
|
@@ -0,0 +1,73 @@
|
|
1
|
+
export declare class CodeGenerator {
|
2
|
+
static TIME_WINDOW_MS: number;
|
3
|
+
static CODE_DIGITS: number;
|
4
|
+
static MIN_PREFIX_LENGTH: number;
|
5
|
+
static MAX_PREFIX_LENGTH: number;
|
6
|
+
/**
|
7
|
+
* Validate prefix format
|
8
|
+
* @param prefix - The prefix to validate
|
9
|
+
* @returns True if prefix is valid, false otherwise
|
10
|
+
*/
|
11
|
+
static validatePrefix(prefix: string): boolean;
|
12
|
+
/**
|
13
|
+
* Normalize prefix - convert "DEFAULT" to empty string, validate others
|
14
|
+
* @param prefix - The prefix to normalize
|
15
|
+
* @returns Normalized prefix
|
16
|
+
* @throws Error if prefix is invalid
|
17
|
+
*/
|
18
|
+
static normalizePrefix(prefix: string): string;
|
19
|
+
/**
|
20
|
+
* Generate a deterministic 8-digit code based on public key, prefix, and timestamp
|
21
|
+
* @param pubkey - Solana wallet public key (base58)
|
22
|
+
* @param signature - User's signature string
|
23
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
24
|
+
* @param timestamp - UNIX timestamp in milliseconds (defaults to now)
|
25
|
+
* @returns Object containing code, issuedAt, and expiresAt timestamps
|
26
|
+
*/
|
27
|
+
static generateCode(pubkey: string, signature: string, prefix?: string, timestamp?: number): {
|
28
|
+
code: string;
|
29
|
+
issuedAt: number;
|
30
|
+
expiresAt: number;
|
31
|
+
};
|
32
|
+
/**
|
33
|
+
* Derive the full SHA-256 hash for storage or encryption key generation
|
34
|
+
* @param pubkey - Solana wallet public key (base58)
|
35
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
36
|
+
* @param timestamp - UNIX timestamp in milliseconds (defaults to now)
|
37
|
+
* @returns Full SHA-256 hash string
|
38
|
+
*/
|
39
|
+
static deriveCodeHash(pubkey: string, prefix?: string, timestamp?: number): string;
|
40
|
+
/**
|
41
|
+
* Generate the message that should be signed for code verification
|
42
|
+
* @param code - The generated 8-digit code
|
43
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
44
|
+
* @returns Message string in format "actioncodes:<code>:<timestamp>"
|
45
|
+
*/
|
46
|
+
static generateCodeSignatureMessage(code: string, timestamp: number): string;
|
47
|
+
/**
|
48
|
+
* Get the expected code for a given public key and timestamp
|
49
|
+
* @param pubkey - Solana wallet public key (base58)
|
50
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
51
|
+
* @param signature - User's signature string
|
52
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
53
|
+
* @returns 8-digit numeric string
|
54
|
+
*/
|
55
|
+
static getExpectedCode(pubkey: string, timestamp: number, signature: string, prefix?: string): string;
|
56
|
+
/**
|
57
|
+
* Validate if a code matches the expected code for a given public key and timestamp
|
58
|
+
* @param code - The code to validate
|
59
|
+
* @param pubkey - Solana wallet public key (base58)
|
60
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
61
|
+
* @param signature - User's signature string
|
62
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
63
|
+
* @returns True if code matches expected code and timestamp is valid
|
64
|
+
*/
|
65
|
+
static validateCode(code: string, pubkey: string, timestamp: number, signature: string, prefix?: string): boolean;
|
66
|
+
/**
|
67
|
+
* Check if a timestamp falls within a valid time window
|
68
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
69
|
+
* @returns True if timestamp is valid
|
70
|
+
*/
|
71
|
+
static isValidTimestamp(timestamp: number): boolean;
|
72
|
+
}
|
73
|
+
//# sourceMappingURL=codegen.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAGA,qBAAa,aAAa;IACtB,MAAM,CAAC,cAAc,SAAY;IACjC,MAAM,CAAC,WAAW,SAAe;IACjC,MAAM,CAAC,iBAAiB,SAAqB;IAC7C,MAAM,CAAC,iBAAiB,SAAqB;IAE7C;;;;OAIG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAM9C;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAQ9C;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAAkB,EAC1B,SAAS,GAAE,MAAmB,GAC/B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAmBxD;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAAkB,EAC1B,SAAS,CAAC,EAAE,MAAM,GACnB,MAAM;IAQT;;;;;OAKG;IACH,MAAM,CAAC,4BAA4B,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAI5E;;;;;;;OAOG;IACH,MAAM,CAAC,eAAe,CAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAAkB,GAC3B,MAAM;IAIT;;;;;;;;OAQG;IACH,MAAM,CAAC,YAAY,CACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAAkB,GAC3B,OAAO;IAOV;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAGtD"}
|
package/dist/codegen.js
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.CodeGenerator = void 0;
|
4
|
+
const js_sha256_1 = require("js-sha256");
|
5
|
+
const constants_1 = require("./constants");
|
6
|
+
class CodeGenerator {
|
7
|
+
/**
|
8
|
+
* Validate prefix format
|
9
|
+
* @param prefix - The prefix to validate
|
10
|
+
* @returns True if prefix is valid, false otherwise
|
11
|
+
*/
|
12
|
+
static validatePrefix(prefix) {
|
13
|
+
if (prefix === "DEFAULT")
|
14
|
+
return true;
|
15
|
+
if (prefix.length < this.MIN_PREFIX_LENGTH || prefix.length > this.MAX_PREFIX_LENGTH)
|
16
|
+
return false;
|
17
|
+
return /^[A-Za-z]+$/.test(prefix);
|
18
|
+
}
|
19
|
+
/**
|
20
|
+
* Normalize prefix - convert "DEFAULT" to empty string, validate others
|
21
|
+
* @param prefix - The prefix to normalize
|
22
|
+
* @returns Normalized prefix
|
23
|
+
* @throws Error if prefix is invalid
|
24
|
+
*/
|
25
|
+
static normalizePrefix(prefix) {
|
26
|
+
if (prefix === "DEFAULT")
|
27
|
+
return "";
|
28
|
+
if (!this.validatePrefix(prefix)) {
|
29
|
+
throw new Error(`Invalid prefix: ${prefix}. Must be 3-12 letters or "DEFAULT"`);
|
30
|
+
}
|
31
|
+
return prefix.toUpperCase();
|
32
|
+
}
|
33
|
+
/**
|
34
|
+
* Generate a deterministic 8-digit code based on public key, prefix, and timestamp
|
35
|
+
* @param pubkey - Solana wallet public key (base58)
|
36
|
+
* @param signature - User's signature string
|
37
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
38
|
+
* @param timestamp - UNIX timestamp in milliseconds (defaults to now)
|
39
|
+
* @returns Object containing code, issuedAt, and expiresAt timestamps
|
40
|
+
*/
|
41
|
+
static generateCode(pubkey, signature, prefix = "DEFAULT", timestamp = Date.now()) {
|
42
|
+
const normalizedPrefix = this.normalizePrefix(prefix);
|
43
|
+
const input = `${normalizedPrefix}:${pubkey}:${timestamp}:${signature}`;
|
44
|
+
const hash = (0, js_sha256_1.sha256)(input);
|
45
|
+
const raw = parseInt(hash.slice(0, 16), 16);
|
46
|
+
const mod = 10 ** this.CODE_DIGITS;
|
47
|
+
const code = raw % mod;
|
48
|
+
const issuedAt = timestamp;
|
49
|
+
const expiresAt = issuedAt + this.TIME_WINDOW_MS;
|
50
|
+
return {
|
51
|
+
code: code.toString().padStart(this.CODE_DIGITS, "0"),
|
52
|
+
issuedAt,
|
53
|
+
expiresAt
|
54
|
+
};
|
55
|
+
}
|
56
|
+
/**
|
57
|
+
* Derive the full SHA-256 hash for storage or encryption key generation
|
58
|
+
* @param pubkey - Solana wallet public key (base58)
|
59
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
60
|
+
* @param timestamp - UNIX timestamp in milliseconds (defaults to now)
|
61
|
+
* @returns Full SHA-256 hash string
|
62
|
+
*/
|
63
|
+
static deriveCodeHash(pubkey, prefix = "DEFAULT", timestamp) {
|
64
|
+
const normalizedPrefix = this.normalizePrefix(prefix);
|
65
|
+
const ts = timestamp ?? Date.now();
|
66
|
+
const input = `${normalizedPrefix}:${pubkey}:${ts}`;
|
67
|
+
const hash = (0, js_sha256_1.sha256)(input);
|
68
|
+
return hash;
|
69
|
+
}
|
70
|
+
/**
|
71
|
+
* Generate the message that should be signed for code verification
|
72
|
+
* @param code - The generated 8-digit code
|
73
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
74
|
+
* @returns Message string in format "actioncodes:<code>:<timestamp>"
|
75
|
+
*/
|
76
|
+
static generateCodeSignatureMessage(code, timestamp) {
|
77
|
+
return `${constants_1.PROTOCOL_PREFIX}:${code}:${timestamp}`;
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Get the expected code for a given public key and timestamp
|
81
|
+
* @param pubkey - Solana wallet public key (base58)
|
82
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
83
|
+
* @param signature - User's signature string
|
84
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
85
|
+
* @returns 8-digit numeric string
|
86
|
+
*/
|
87
|
+
static getExpectedCode(pubkey, timestamp, signature, prefix = "DEFAULT") {
|
88
|
+
return this.generateCode(pubkey, signature, prefix, timestamp).code;
|
89
|
+
}
|
90
|
+
/**
|
91
|
+
* Validate if a code matches the expected code for a given public key and timestamp
|
92
|
+
* @param code - The code to validate
|
93
|
+
* @param pubkey - Solana wallet public key (base58)
|
94
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
95
|
+
* @param signature - User's signature string
|
96
|
+
* @param prefix - Optional namespace prefix (default: "DEFAULT")
|
97
|
+
* @returns True if code matches expected code and timestamp is valid
|
98
|
+
*/
|
99
|
+
static validateCode(code, pubkey, timestamp, signature, prefix = "DEFAULT") {
|
100
|
+
const expectedCode = this.getExpectedCode(pubkey, timestamp, signature, prefix);
|
101
|
+
const now = Date.now();
|
102
|
+
const isTimeValid = timestamp >= 0 && timestamp <= now && now <= timestamp + this.TIME_WINDOW_MS;
|
103
|
+
return code === expectedCode && isTimeValid;
|
104
|
+
}
|
105
|
+
/**
|
106
|
+
* Check if a timestamp falls within a valid time window
|
107
|
+
* @param timestamp - UNIX timestamp in milliseconds
|
108
|
+
* @returns True if timestamp is valid
|
109
|
+
*/
|
110
|
+
static isValidTimestamp(timestamp) {
|
111
|
+
return timestamp >= 0 && timestamp <= Date.now() + this.TIME_WINDOW_MS;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
exports.CodeGenerator = CodeGenerator;
|
115
|
+
CodeGenerator.TIME_WINDOW_MS = constants_1.CODE_TTL;
|
116
|
+
CodeGenerator.CODE_DIGITS = constants_1.CODE_LENGTH;
|
117
|
+
CodeGenerator.MIN_PREFIX_LENGTH = constants_1.MIN_PREFIX_LENGTH;
|
118
|
+
CodeGenerator.MAX_PREFIX_LENGTH = constants_1.MAX_PREFIX_LENGTH;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
export declare const PROTOCOL_VERSION = "1";
|
2
|
+
export declare const PROTOCOL_PREFIX = "actioncodes";
|
3
|
+
export declare const CODE_LENGTH = 8;
|
4
|
+
export declare const CODE_TTL: number;
|
5
|
+
export declare const PROTOCOL_CODE_PREFIX = "DEFAULT";
|
6
|
+
export declare const MIN_PREFIX_LENGTH = 3;
|
7
|
+
export declare const MAX_PREFIX_LENGTH = 12;
|
8
|
+
export declare const SUPPORTED_CHAINS: readonly ["solana"];
|
9
|
+
export type SupportedChain = (typeof SUPPORTED_CHAINS)[number];
|
10
|
+
//# sourceMappingURL=constants.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,MAAM,CAAC;AACpC,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAAgB,CAAC;AACtC,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAC9C,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,gBAAgB,qBAAsB,CAAC;AACpD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.SUPPORTED_CHAINS = exports.MAX_PREFIX_LENGTH = exports.MIN_PREFIX_LENGTH = exports.PROTOCOL_CODE_PREFIX = exports.CODE_TTL = exports.CODE_LENGTH = exports.PROTOCOL_PREFIX = exports.PROTOCOL_VERSION = void 0;
|
4
|
+
exports.PROTOCOL_VERSION = "1";
|
5
|
+
exports.PROTOCOL_PREFIX = "actioncodes";
|
6
|
+
exports.CODE_LENGTH = 8;
|
7
|
+
exports.CODE_TTL = 1000 * 60 * 2; // 2 minutes
|
8
|
+
exports.PROTOCOL_CODE_PREFIX = "DEFAULT";
|
9
|
+
exports.MIN_PREFIX_LENGTH = 3;
|
10
|
+
exports.MAX_PREFIX_LENGTH = 12;
|
11
|
+
exports.SUPPORTED_CHAINS = ["solana"];
|
package/dist/index.d.ts
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
export * from './adapters/solana';
|
2
|
+
export * from './adapters/base';
|
3
|
+
export * from './codegen';
|
4
|
+
export * from './constants';
|
5
|
+
export * from './meta';
|
6
|
+
export * from './actioncode';
|
7
|
+
export * from './protocol';
|
8
|
+
export type { SolanaTransaction } from './adapters/solana';
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAG3B,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
|
+
};
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
+
__exportStar(require("./adapters/solana"), exports);
|
18
|
+
__exportStar(require("./adapters/base"), exports);
|
19
|
+
__exportStar(require("./codegen"), exports);
|
20
|
+
__exportStar(require("./constants"), exports);
|
21
|
+
__exportStar(require("./meta"), exports);
|
22
|
+
__exportStar(require("./actioncode"), exports);
|
23
|
+
__exportStar(require("./protocol"), exports);
|
package/dist/meta.d.ts
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
/**
|
2
|
+
* Protocol meta structure for code verification
|
3
|
+
*/
|
4
|
+
export interface ProtocolMetaV1 {
|
5
|
+
version: string;
|
6
|
+
prefix: string;
|
7
|
+
initiator: string;
|
8
|
+
id: string;
|
9
|
+
iss?: string;
|
10
|
+
params?: string;
|
11
|
+
}
|
12
|
+
/**
|
13
|
+
* Protocol meta parser for structured memo/message parsing
|
14
|
+
*/
|
15
|
+
export declare class ProtocolMetaParser {
|
16
|
+
private static readonly PROTOCOL_REGEX;
|
17
|
+
/**
|
18
|
+
* Parse protocol meta from string
|
19
|
+
* @param metaString - The protocol meta string to parse
|
20
|
+
* @returns Parsed ProtocolMeta object or null if invalid
|
21
|
+
*/
|
22
|
+
static parse(metaString: string): ProtocolMetaV1 | null;
|
23
|
+
/**
|
24
|
+
* Serialize ProtocolMeta to string
|
25
|
+
* @param meta - The protocol meta to serialize
|
26
|
+
* @returns Serialized protocol meta string
|
27
|
+
*/
|
28
|
+
static serialize(meta: ProtocolMetaV1): string;
|
29
|
+
/**
|
30
|
+
* Create protocol meta from code and parameters
|
31
|
+
* @param initiator - The initiator public key
|
32
|
+
* @param iss - The issuer (protocol authority)
|
33
|
+
* @param prefix - The prefix (default: "DEFAULT")
|
34
|
+
* @param params - Optional parameters
|
35
|
+
* @param timestamp - Optional timestamp
|
36
|
+
* @returns ProtocolMeta object
|
37
|
+
*/
|
38
|
+
static fromInitiator(initiator: string, iss: string, prefix?: string, params?: string, timestamp?: number): ProtocolMetaV1;
|
39
|
+
/**
|
40
|
+
* Validate if a code matches the protocol meta
|
41
|
+
* @param meta - The protocol meta to validate against
|
42
|
+
* @param timestamp - Optional timestamp for validation (if not provided, uses current time)
|
43
|
+
* @returns True if the meta is valid
|
44
|
+
*/
|
45
|
+
static validateCode(meta: ProtocolMetaV1, timestamp?: number): boolean;
|
46
|
+
/**
|
47
|
+
* Validate if a code matches the protocol meta by parsing from string
|
48
|
+
* @param metaString - The protocol meta string to validate against
|
49
|
+
* @param timestamp - Optional timestamp for validation (if not provided, uses current time)
|
50
|
+
* @returns True if the code matches the meta
|
51
|
+
*/
|
52
|
+
static validateMetaFromString(metaString: string, timestamp?: number): boolean;
|
53
|
+
}
|
54
|
+
//# sourceMappingURL=meta.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAqF;IAE3H;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAuBvD;;;;OAIG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM;IAU9C;;;;;;;;OAQG;IACH,MAAM,CAAC,aAAa,CAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,MAAkB,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc;IAajB;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAKtE;;;;;OAKG;IACH,MAAM,CAAC,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;CAO/E"}
|