@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.
Files changed (65) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +55 -0
  3. package/dist/actioncode.d.ts +114 -0
  4. package/dist/actioncode.d.ts.map +1 -0
  5. package/dist/actioncode.js +159 -0
  6. package/dist/adapters/base.d.ts +52 -0
  7. package/dist/adapters/base.d.ts.map +1 -0
  8. package/dist/adapters/base.js +41 -0
  9. package/dist/adapters/solana/index.d.ts +2 -0
  10. package/dist/adapters/solana/index.d.ts.map +1 -0
  11. package/dist/adapters/solana/index.js +17 -0
  12. package/dist/adapters/solana/solana.d.ts +84 -0
  13. package/dist/adapters/solana/solana.d.ts.map +1 -0
  14. package/dist/adapters/solana/solana.js +223 -0
  15. package/dist/codegen.d.ts +73 -0
  16. package/dist/codegen.d.ts.map +1 -0
  17. package/dist/codegen.js +118 -0
  18. package/dist/constants.d.ts +10 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +11 -0
  21. package/dist/index.d.ts +9 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +23 -0
  24. package/dist/meta.d.ts +54 -0
  25. package/dist/meta.d.ts.map +1 -0
  26. package/dist/meta.js +91 -0
  27. package/dist/protocol.d.ts +167 -0
  28. package/dist/protocol.d.ts.map +1 -0
  29. package/dist/protocol.js +280 -0
  30. package/docs/README.md +59 -0
  31. package/docs/_media/LICENSE +201 -0
  32. package/docs/_media/README.md +28 -0
  33. package/docs/actioncode/README.md +21 -0
  34. package/docs/actioncode/classes/ActionCode.md +412 -0
  35. package/docs/actioncode/interfaces/ActionCodeFields.md +95 -0
  36. package/docs/actioncode/interfaces/ActionCodeMetadata.md +25 -0
  37. package/docs/actioncode/interfaces/ActionCodeTransaction.md +39 -0
  38. package/docs/actioncode/type-aliases/ActionCodeStatus.md +11 -0
  39. package/docs/adapters/base/README.md +11 -0
  40. package/docs/adapters/base/classes/BaseChainAdapter.md +222 -0
  41. package/docs/adapters/solana/README.md +19 -0
  42. package/docs/adapters/solana/solana/README.md +15 -0
  43. package/docs/adapters/solana/solana/classes/SolanaAdapter.md +306 -0
  44. package/docs/adapters/solana/solana/type-aliases/SolanaTransaction.md +13 -0
  45. package/docs/codegen/README.md +11 -0
  46. package/docs/codegen/classes/CodeGenerator.md +337 -0
  47. package/docs/constants/README.md +22 -0
  48. package/docs/constants/type-aliases/SupportedChain.md +11 -0
  49. package/docs/constants/variables/CODE_LENGTH.md +11 -0
  50. package/docs/constants/variables/CODE_TTL.md +11 -0
  51. package/docs/constants/variables/MAX_PREFIX_LENGTH.md +11 -0
  52. package/docs/constants/variables/MIN_PREFIX_LENGTH.md +11 -0
  53. package/docs/constants/variables/PROTOCOL_CODE_PREFIX.md +11 -0
  54. package/docs/constants/variables/PROTOCOL_PREFIX.md +11 -0
  55. package/docs/constants/variables/PROTOCOL_VERSION.md +11 -0
  56. package/docs/constants/variables/SUPPORTED_CHAINS.md +11 -0
  57. package/docs/index/README.md +139 -0
  58. package/docs/meta/README.md +15 -0
  59. package/docs/meta/classes/ProtocolMetaParser.md +177 -0
  60. package/docs/meta/interfaces/ProtocolMetaV1.md +59 -0
  61. package/docs/modules.md +17 -0
  62. package/docs/protocol/README.md +51 -0
  63. package/docs/protocol/classes/ActionCodesProtocol.md +616 -0
  64. package/docs/protocol/interfaces/ProtocolConfig.md +71 -0
  65. 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"}
@@ -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"];
@@ -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"}