@actioncodes/protocol 1.2.2 → 2.0.1

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 (144) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +318 -33
  3. package/dist/ActionCodesProtocol.d.ts +37 -0
  4. package/dist/ActionCodesProtocol.d.ts.map +1 -0
  5. package/dist/adapters/BaseChainAdapter.d.ts +22 -0
  6. package/dist/adapters/BaseChainAdapter.d.ts.map +1 -0
  7. package/dist/adapters/SolanaAdapter.d.ts +44 -0
  8. package/dist/adapters/SolanaAdapter.d.ts.map +1 -0
  9. package/dist/constants.d.ts +6 -8
  10. package/dist/constants.d.ts.map +1 -1
  11. package/dist/errors.d.ts +63 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/index.cjs +3 -0
  14. package/dist/index.cjs.map +25 -0
  15. package/dist/index.d.ts +10 -8
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +3 -36
  18. package/dist/index.js.map +25 -0
  19. package/dist/strategy/DelegationStrategy.d.ts +45 -0
  20. package/dist/strategy/DelegationStrategy.d.ts.map +1 -0
  21. package/dist/strategy/WalletStrategy.d.ts +8 -0
  22. package/dist/strategy/WalletStrategy.d.ts.map +1 -0
  23. package/dist/types.d.ts +40 -0
  24. package/dist/types.d.ts.map +1 -0
  25. package/dist/utils/canonical.d.ts +5 -0
  26. package/dist/utils/canonical.d.ts.map +1 -0
  27. package/dist/utils/crypto.d.ts +13 -0
  28. package/dist/utils/crypto.d.ts.map +1 -0
  29. package/dist/utils/protocolMeta.d.ts +16 -0
  30. package/dist/utils/protocolMeta.d.ts.map +1 -0
  31. package/docs/ActionCodesProtocol/README.md +11 -0
  32. package/docs/ActionCodesProtocol/classes/ActionCodesProtocol.md +147 -0
  33. package/docs/README.md +10 -50
  34. package/docs/adapters/BaseChainAdapter/README.md +20 -0
  35. package/docs/adapters/BaseChainAdapter/classes/BaseChainAdapter.md +56 -0
  36. package/docs/adapters/BaseChainAdapter/interfaces/BaseContext.md +17 -0
  37. package/docs/adapters/BaseChainAdapter/interfaces/ChainAdapter.md +33 -0
  38. package/docs/adapters/BaseChainAdapter/type-aliases/ChainContext.md +23 -0
  39. package/docs/adapters/NodeCryptoAdapter/README.md +15 -0
  40. package/docs/adapters/NodeCryptoAdapter/classes/NodeCryptoAdapter.md +254 -0
  41. package/docs/adapters/NodeCryptoAdapter/type-aliases/NodeCryptoContext.md +27 -0
  42. package/docs/adapters/SolanaAdapter/README.md +16 -0
  43. package/docs/adapters/SolanaAdapter/classes/SolanaAdapter.md +190 -0
  44. package/docs/adapters/SolanaAdapter/type-aliases/SolanaContext.md +27 -0
  45. package/docs/adapters/SolanaAdapter/type-aliases/SolanaTransaction.md +13 -0
  46. package/docs/constants/README.md +8 -13
  47. package/docs/constants/variables/CODE_CHARSET_DIGITS.md +11 -0
  48. package/docs/constants/variables/CODE_DEFAULT_LENGTH.md +11 -0
  49. package/docs/constants/variables/CODE_MAX_LENGTH.md +11 -0
  50. package/docs/constants/variables/CODE_MIN_LENGTH.md +11 -0
  51. package/docs/constants/variables/PROTOCOL_META_MAX_BYTES.md +11 -0
  52. package/docs/constants/variables/PROTOCOL_NORMALIZATION.md +11 -0
  53. package/docs/constants/variables/SUPPORTED_CHAINS.md +3 -3
  54. package/docs/errors/README.md +22 -0
  55. package/docs/errors/classes/ExpiredCodeError.md +695 -0
  56. package/docs/errors/classes/InvalidCodeFormatError.md +691 -0
  57. package/docs/errors/classes/InvalidPubkeyFormatError.md +691 -0
  58. package/docs/errors/classes/InvalidSignatureError.md +687 -0
  59. package/docs/errors/classes/MetaMismatchError.md +695 -0
  60. package/docs/errors/classes/MissingMetaError.md +681 -0
  61. package/docs/errors/classes/ProtocolError.md +637 -0
  62. package/docs/errors/classes/TransactionNotSignedByIntendedOwnerError.md +691 -0
  63. package/docs/errors/enumerations/ProtocolErrorCode.md +121 -0
  64. package/docs/index/README.md +83 -41
  65. package/docs/modules.md +12 -9
  66. package/docs/strategy/WalletStrategy/README.md +11 -0
  67. package/docs/strategy/WalletStrategy/classes/WalletStrategy.md +67 -0
  68. package/docs/types/README.md +14 -0
  69. package/docs/types/interfaces/ActionCode.md +65 -0
  70. package/docs/types/interfaces/CanonicalMessageParts.md +33 -0
  71. package/docs/types/interfaces/CodeGenerationConfig.md +33 -0
  72. package/docs/types/interfaces/CodeGenerationResult.md +25 -0
  73. package/docs/utils/canonical/README.md +16 -0
  74. package/docs/utils/canonical/functions/serializeCanonical.md +21 -0
  75. package/docs/utils/canonical/variables/CANONICAL_MESSAGE_PREFIX.md +11 -0
  76. package/docs/utils/canonical/variables/CANONICAL_MESSAGE_VERSION.md +11 -0
  77. package/docs/utils/crypto/README.md +18 -0
  78. package/docs/utils/crypto/functions/base32EncodeCrockford.md +21 -0
  79. package/docs/utils/crypto/functions/codeHash.md +21 -0
  80. package/docs/utils/crypto/functions/digestToDigits.md +25 -0
  81. package/docs/utils/crypto/functions/generateRandomSecret.md +15 -0
  82. package/docs/utils/crypto/functions/hkdfSha256.md +35 -0
  83. package/docs/utils/crypto/functions/hmacSha256.md +25 -0
  84. package/docs/utils/crypto/functions/sha256.md +21 -0
  85. package/docs/utils/crypto/functions/truncateBits.md +25 -0
  86. package/docs/utils/protocolMeta/README.md +21 -0
  87. package/docs/utils/protocolMeta/functions/buildProtocolMeta.md +21 -0
  88. package/docs/utils/protocolMeta/functions/parseProtocolMeta.md +21 -0
  89. package/docs/utils/protocolMeta/functions/validateProtocolMetaFormat.md +21 -0
  90. package/docs/utils/protocolMeta/interfaces/ProtocolMetaFields.md +41 -0
  91. package/docs/utils/protocolMeta/variables/SCHEME.md +11 -0
  92. package/package.json +42 -47
  93. package/dist/actioncode.d.ts +0 -120
  94. package/dist/actioncode.d.ts.map +0 -1
  95. package/dist/actioncode.js +0 -186
  96. package/dist/adapters/base.d.ts +0 -93
  97. package/dist/adapters/base.d.ts.map +0 -1
  98. package/dist/adapters/base.js +0 -65
  99. package/dist/adapters/solana/index.d.ts +0 -2
  100. package/dist/adapters/solana/index.d.ts.map +0 -1
  101. package/dist/adapters/solana/index.js +0 -30
  102. package/dist/adapters/solana/solana.d.ts +0 -113
  103. package/dist/adapters/solana/solana.d.ts.map +0 -1
  104. package/dist/adapters/solana/solana.js +0 -537
  105. package/dist/codegen.d.ts +0 -76
  106. package/dist/codegen.d.ts.map +0 -1
  107. package/dist/codegen.js +0 -211
  108. package/dist/constants.js +0 -24
  109. package/dist/meta.d.ts +0 -54
  110. package/dist/meta.d.ts.map +0 -1
  111. package/dist/meta.js +0 -104
  112. package/dist/protocol.d.ts +0 -179
  113. package/dist/protocol.d.ts.map +0 -1
  114. package/dist/protocol.js +0 -390
  115. package/docs/_media/LICENSE +0 -201
  116. package/docs/_media/README.md +0 -28
  117. package/docs/actioncode/README.md +0 -21
  118. package/docs/actioncode/classes/ActionCode.md +0 -430
  119. package/docs/actioncode/interfaces/ActionCodeFields.md +0 -89
  120. package/docs/actioncode/interfaces/ActionCodeMetadata.md +0 -25
  121. package/docs/actioncode/interfaces/ActionCodeTransaction.md +0 -57
  122. package/docs/actioncode/type-aliases/ActionCodeStatus.md +0 -11
  123. package/docs/adapters/base/README.md +0 -11
  124. package/docs/adapters/base/classes/BaseChainAdapter.md +0 -396
  125. package/docs/adapters/solana/README.md +0 -19
  126. package/docs/adapters/solana/solana/README.md +0 -15
  127. package/docs/adapters/solana/solana/classes/SolanaAdapter.md +0 -506
  128. package/docs/adapters/solana/solana/type-aliases/SolanaTransaction.md +0 -13
  129. package/docs/codegen/README.md +0 -11
  130. package/docs/codegen/classes/CodeGenerator.md +0 -341
  131. package/docs/constants/type-aliases/SupportedChain.md +0 -11
  132. package/docs/constants/variables/CODE_LENGTH.md +0 -11
  133. package/docs/constants/variables/CODE_TTL.md +0 -11
  134. package/docs/constants/variables/MAX_PREFIX_LENGTH.md +0 -11
  135. package/docs/constants/variables/MIN_PREFIX_LENGTH.md +0 -11
  136. package/docs/constants/variables/PROTOCOL_CODE_PREFIX.md +0 -11
  137. package/docs/constants/variables/PROTOCOL_PREFIX.md +0 -11
  138. package/docs/constants/variables/PROTOCOL_VERSION.md +0 -11
  139. package/docs/meta/README.md +0 -15
  140. package/docs/meta/classes/ProtocolMetaParser.md +0 -177
  141. package/docs/meta/interfaces/ProtocolMetaV1.md +0 -59
  142. package/docs/protocol/README.md +0 -51
  143. package/docs/protocol/classes/ActionCodesProtocol.md +0 -676
  144. package/docs/protocol/interfaces/ProtocolConfig.md +0 -71
package/LICENSE CHANGED
@@ -198,4 +198,4 @@
198
198
  distributed under the License is distributed on an "AS IS" BASIS,
199
199
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
200
  See the License for the specific language governing permissions and
201
- limitations under the License.
201
+ limitations under the License.
package/README.md CHANGED
@@ -1,55 +1,340 @@
1
- # 🛡️ Action Codes Protocol
1
+ ## Action Codes Protocol
2
2
 
3
- ![Coverage](https://img.shields.io/badge/coverage-98%-brightgreen)
3
+ The Action Codes Protocol is a lightweight way to prove intent and authorize actions across blockchains, apps, and wallets.
4
+ Instead of heavy signature popups or complex flows, it uses short-lived one-time codes derived from canonical cryptographic messages.
4
5
 
5
- **Action Codes Protocol** enables short-lived, cryptographically verifiable action codes that authorize blockchain transactions and intents without requiring live wallet sessions.
6
+ ### This enables:
7
+ - Secure intent binding – the code is cryptographically tied to a wallet/public key.
8
+ - Fast verification – relayers/servers can validate in microseconds.
9
+ - Cross-chain support – adapters handle chain-specific quirks (currently we are supporting Solana)
10
+ - Simple dev UX – just generate → sign → verify.
6
11
 
7
- This repository contains the canonical specifications, SDK modules, and chain adapter interfaces that implement the Action Codes Protocol.
12
+ ### What's new in v2 (compared to [v1](https://github.com/otaprotocol/actioncodes))
13
+ - Now we use Bun as core library. We are down to ~3ms per code signature verification on commodity hardware.
14
+ - Canonical Messages only → No ambiguity. Codes are always derived from a canonical serialization (serializeCanonical).
15
+ - No AIPs (Action Codes Improvement Proposals) → Overkill for lightweight protocol.
16
+ - Chain Adapters simplified → They don't enforce business rules; they just provide utilities:
17
+ - createProtocolMetaIx (for attaching metadata)
18
+ - parseMeta / verifyTransactionMatchesCode (for checking integrity)
19
+ - verifyTransactionSignedByIntentOwner (optional stronger guarantee).
20
+ - Errors are typed → Clear ProtocolError.* categories instead of generic fails.
8
21
 
9
- ---
22
+ ### Core Concepts
10
23
 
11
- ## Key Features
24
+ 1. Action Codes
25
+ - A short-lived, one-time code bound to a wallet/public key.
26
+ - Generated using HMAC/HKDF and canonical serialization.
12
27
 
13
- - 🔐 **Deterministic Code Generation**
14
- Users can generate time-limited codes directly in their wallet or client, without external servers.
28
+ 2. Protocol Meta
29
+ - The "payload" carried with transactions to tie them to action codes.
30
+ - Versioned, deterministic, size-limited.
31
+ - Perfect for attaching to transactions or off-chain messages for tracing.
15
32
 
16
- - **Signature-Based Verification**
17
- Codes are signed by the wallet, and transactions must be signed by protocol-authorized relayers.
33
+ 3. Canonical Message
34
+ - A deterministic JSON serialization of (pubkey, code, timestamp, optional secret)
35
+ - Always signed by the user's wallet.
36
+ - Prevents replay / tampering.
18
37
 
19
- - 🧩 **Meta-Based Intent Encoding**
20
- Each transaction carries an encoded `meta` string for verifiable context across chains.
38
+ ## Strategy Architecture
21
39
 
22
- - 🧱 **Chain-Agnostic Design**
23
- Works on Solana today; built for future EVM, Cosmos, and more.
40
+ The Action Codes Protocol supports two main strategies for generating and validating codes:
24
41
 
25
- - 🌐 **Prefix Namespace System**
26
- Enables ecosystem-wide namespacing (e.g. `JUP`, `ME`) for branded intents and UIs.
42
+ ### 1. Wallet Strategy (Direct)
27
43
 
28
- ---
44
+ The **Wallet Strategy** is the simplest approach where codes are generated directly from a user's wallet.
29
45
 
30
- ## 📦 Repository Structure
46
+ #### How it works:
47
+ ```typescript
48
+ // 1. Get canonical message for signing
49
+ const canonicalMessage = protocol.getCanonicalMessageParts("user-wallet-address");
31
50
 
51
+ // 2. Sign the canonical message with user's wallet
52
+ const signature = await userWallet.signMessage(canonicalMessage);
53
+
54
+ // 3. Generate code with the signed canonical message (secret is optional)
55
+ const result = await protocol.generateCode("wallet", canonicalMessage, signature);
56
+ // Optional: provide secret for enhanced security
57
+ // const result = await protocol.generateCode("wallet", canonicalMessage, signature, "optional-secret");
58
+
59
+ // 4. Validate code
60
+ const isValid = await protocol.validateCode("wallet", result.actionCode, {
61
+ chain: "solana",
62
+ pubkey: "user-wallet-address",
63
+ signature: signature
64
+ });
65
+ ```
66
+
67
+ #### Key Features:
68
+ - **Signature-based security** - Codes require a valid signature over the canonical message (prevents public key + timestamp attacks)
69
+ - **Direct wallet binding** - Codes are cryptographically tied to the user's public key
70
+ - **Optional secrets** - Users can provide a secret for enhanced security (uses HMAC), or omit it (uses SHA256)
71
+ - **Immediate validation** - No delegation certificates needed
72
+ - **Perfect for** - Direct user interactions, simple authentication flows
73
+
74
+ #### Security Model:
75
+ - **Signature verification** - All codes require a valid signature over the canonical message
76
+ - **Public key + timestamp attack prevention** - Signatures prevent attackers from generating codes with just public key + timestamp
77
+ - Codes are bound to the specific public key
78
+ - Optional secret provides additional entropy (HMAC vs SHA256)
79
+ - Time-based expiration prevents replay attacks
80
+ - Canonical message signing ensures integrity
81
+
82
+ ### 2. Delegation Strategy (Advanced)
83
+
84
+ The **Delegation Strategy** allows users to pre-authorize actions through delegation certificates, enabling more complex workflows like relayer services.
85
+
86
+ #### How it works:
87
+
88
+ ##### Step 1: Create Delegation Certificate
89
+ ```typescript
90
+ // User creates a delegation certificate template
91
+ const template = await protocol.createDelegationCertificateTemplate(
92
+ userPublicKey,
93
+ 3600000, // 1 hour expiration
94
+ "solana"
95
+ );
96
+
97
+ // User signs the certificate
98
+ const message = DelegationStrategy.serializeCertificate(template);
99
+ const signature = await userWallet.signMessage(message);
100
+
101
+ const certificate: DelegationCertificate = {
102
+ ...template,
103
+ signature: signature
104
+ };
105
+ ```
106
+
107
+ ##### Step 2: Generate Delegated Codes
108
+ ```typescript
109
+ // Generate codes using the delegation certificate
110
+ const result = await protocol.generateCode("delegation", certificate);
111
+ const actionCode = result.actionCode;
112
+ ```
113
+
114
+ ##### Step 3: Validate Delegated Codes
115
+ ```typescript
116
+ // Validate the delegated code with the certificate
117
+ const isValid = await protocol.validateCode(actionCode, "delegation", certificate);
118
+ ```
119
+
120
+ #### Key Features:
121
+ - **Pre-authorization** - Users can authorize actions for a limited time
122
+ - **Relayer support** - Third parties can validate codes without generating them
123
+ - **Certificate-based** - Codes are bound to specific delegation certificates
124
+ - **Time-limited** - Certificates have expiration times
125
+ - **Perfect for** - Relayer services, automated systems, complex workflows
126
+
127
+ #### Security Model:
128
+ - **Code-Certificate Binding** - Codes are cryptographically bound to their specific certificate
129
+ - **Signature Verification** - Certificate signatures are verified using chain adapters
130
+ - **Delegation ID** - Each certificate has a unique ID derived from its content + signature
131
+ - **Cross-Certificate Protection** - Codes from one certificate cannot be used with another
132
+ - **Relayer Security** - Relayers can validate codes but cannot generate them without the user's signature
133
+
134
+ #### Important Security Guarantees:
135
+
136
+ 1. **Stolen Delegation IDs are Useless**
137
+ - Delegation IDs are public identifiers (like transaction hashes)
138
+ - They cannot be used to generate or validate codes
139
+ - They're safe to share publicly
140
+
141
+ 2. **Stolen Signatures Cannot Create Valid Codes**
142
+ - Even if an attacker steals a signature, they cannot create valid codes
143
+ - Codes are bound to the ENTIRE certificate (not just the signature)
144
+ - Different certificate data = different code = validation failure
145
+
146
+ 3. **Relayer Code Generation Prevention**
147
+ - Relayers cannot generate codes even with public certificate data
148
+ - Certificate hashes include the signature (private user asset)
149
+ - Only the original user can generate valid codes
150
+
151
+ 4. **Code-Certificate Binding**
152
+ - Codes are cryptographically linked to their specific certificate
153
+ - Cross-certificate attacks are impossible
154
+ - Each certificate produces unique codes
155
+
156
+ #### Delegation Certificate Structure:
157
+ ```typescript
158
+ interface DelegationCertificate {
159
+ version: "1.0";
160
+ delegator: string; // User's public key
161
+ issuedAt: number; // Timestamp when issued
162
+ expiresAt: number; // Expiration timestamp
163
+ nonce: string; // Unique nonce for this certificate
164
+ chain: string; // Target blockchain
165
+ signature: string; // User's signature of the certificate
166
+ }
167
+ ```
168
+
169
+ #### Delegated Action Code Structure:
170
+ ```typescript
171
+ interface DelegatedActionCode {
172
+ code: string; // The actual action code
173
+ pubkey: string; // User's public key
174
+ timestamp: number; // Generation timestamp
175
+ expiresAt: number; // Code expiration
176
+ delegationId: string; // Hash of the certificate (used internally as secret)
177
+ delegatedBy: string; // Who delegated (same as pubkey)
178
+ // Note: secret field is inherited from ActionCode but not used in delegation
179
+ }
180
+ ```
181
+
182
+ ## Use Cases & Examples
183
+
184
+ ### Wallet Strategy Use Cases
185
+
186
+ #### 1. Simple Authentication
187
+ ```typescript
188
+ // User logs into a dApp
189
+ const canonicalMessage = protocol.getCanonicalMessageParts(userWallet.publicKey);
190
+ const signature = await userWallet.signMessage(canonicalMessage);
191
+ const result = await protocol.generateCode("wallet", canonicalMessage, signature);
192
+
193
+ // dApp validates the code
194
+ const isValid = await protocol.validateCode('wallet', result.actionCode, {
195
+ chain: "solana",
196
+ pubkey: userWallet.publicKey,
197
+ signature: signature
198
+ });
32
199
  ```
33
- /src - SDK modules (codegen, meta, validator, blockchain adapters)
34
- /specs - Formal specifications (AIPs)
35
- README.md - You are here
36
- LICENSE - Apache 2.0
200
+
201
+ #### 2. Transaction Authorization
202
+ ```typescript
203
+ // User authorizes a specific transaction
204
+ const canonicalMessage = protocol.getCanonicalMessageParts(userWallet.publicKey);
205
+ const signature = await userWallet.signMessage(canonicalMessage);
206
+ const result = await protocol.generateCode("wallet", canonicalMessage, signature);
207
+ // Optional: add secret for enhanced security
208
+ // const result = await protocol.generateCode("wallet", canonicalMessage, signature, `tx-${transactionHash}`);
209
+
210
+ // Relayer validates before executing
211
+ const isValid = await protocol.validateCode('wallet', result.actionCode, {
212
+ chain: "solana",
213
+ pubkey: userWallet.publicKey,
214
+ signature: signature
215
+ });
216
+ ```
217
+
218
+ ### Delegation Strategy Use Cases
219
+
220
+ #### 1. Relayer Services
221
+ ```typescript
222
+ // User pre-authorizes a relayer for 1 hour
223
+ const certificate = await createDelegationCertificate(userWallet, 3600000);
224
+
225
+ // Relayer can validate codes but not generate them
226
+ const relayer = new RelayerService();
227
+ relayer.registerCertificate(certificate);
228
+
229
+ // User generates codes that relayer can validate
230
+ const actionCode = await protocol.generateCode("delegation", certificate);
231
+ const isValid = relayer.validateCode(actionCode, certificate);
232
+ ```
233
+
234
+ #### 2. Automated Trading Bots
235
+ ```typescript
236
+ // User authorizes trading bot for specific operations
237
+ const tradingCertificate = await createDelegationCertificate(userWallet, 86400000); // 24 hours
238
+
239
+ // Bot can execute trades using delegated codes
240
+ const tradeCode = await protocol.generateCode("delegation", tradingCertificate);
241
+ // Bot executes trade with this code
242
+ ```
243
+
244
+ #### 3. Multi-Signature Workflows
245
+ ```typescript
246
+ // Multiple users can delegate to a shared certificate
247
+ const sharedCertificate = await createSharedDelegationCertificate([
248
+ user1Wallet,
249
+ user2Wallet,
250
+ user3Wallet
251
+ ]);
252
+
253
+ // Any authorized user can generate codes
254
+ const actionCode = await protocol.generateCode("delegation", sharedCertificate);
37
255
  ```
38
256
 
39
- ---
257
+ ## Security Considerations
258
+
259
+ ### What Makes Action Codes Secure?
260
+
261
+ 1. **Cryptographic Binding**
262
+ - Codes are mathematically tied to specific public keys
263
+ - Impossible to forge without the private key
264
+
265
+ 2. **Time-Limited Validity**
266
+ - Codes expire automatically
267
+ - Prevents replay attacks
40
268
 
41
- ## 📄 Specifications
269
+ 3. **One-Time Use**
270
+ - Each code is unique and time-bound
271
+ - Cannot be reused
42
272
 
43
- [Protocol Specifications](./specs/README.md)
273
+ 4. **Delegation Security**
274
+ - Delegation certificates are cryptographically signed
275
+ - Codes are bound to specific certificates
276
+ - Cross-certificate attacks are impossible
44
277
 
45
- - [`AIP-0`](./specs/aip-0.md): Action Codes Protocol Architecture
46
- - [`AIP-1`](./specs/aip-1.md): Protocol Meta Format
47
- - [`AIP-2`](./specs/aip-2.md): Authority Signature Validation
48
- - [`AIP-3`](./specs/aip-3.md): Intent Resolution & Routing
49
- - [`AIP-4`](./specs/aip-4.md): Prefix System
278
+ ### Best Practices
279
+
280
+ 1. **Secret Management**
281
+ - Use cryptographically secure random secrets
282
+ - Don't reuse secrets across different contexts
283
+ - Consider using deterministic secrets based on context
284
+
285
+ 2. **Certificate Expiration**
286
+ - Set appropriate expiration times for delegation certificates
287
+ - Shorter expiration = higher security
288
+ - Longer expiration = better UX
289
+
290
+ 3. **Relayer Security**
291
+ - Only trust relayers with full certificates
292
+ - Never share private keys with relayers
293
+ - Monitor relayer behavior
294
+
295
+ 4. **Code Validation**
296
+ - Always validate codes server-side
297
+ - Check expiration times
298
+ - Verify the binding to the correct public key
299
+
300
+ ## Performance
301
+
302
+ - **Code Generation**: ~1ms per code
303
+ - **Code Validation**: ~3ms per validation
304
+ - **Memory Usage**: Minimal (no state storage required)
305
+ - **Network**: No network calls required for validation
306
+
307
+ ## Getting Started
308
+
309
+ ```bash
310
+ # Install
311
+ npm install @actioncodes/protocol
312
+
313
+ # Basic usage
314
+ import { ActionCodesProtocol } from '@actioncodes/protocol';
315
+
316
+ const protocol = new ActionCodesProtocol();
317
+
318
+ // 1. Get canonical message for signing
319
+ const canonicalMessage = protocol.getCanonicalMessageParts("your-public-key");
320
+
321
+ // 2. Sign the canonical message with your wallet
322
+ const signature = await yourWallet.signMessage(canonicalMessage);
323
+
324
+ // 3. Generate a code with the signed canonical message
325
+ const result = await protocol.generateCode("wallet", canonicalMessage, signature);
326
+ // Optional: add secret for enhanced security
327
+ // const result = await protocol.generateCode("wallet", canonicalMessage, signature, "optional-secret");
328
+
329
+ // 4. Validate a code
330
+ const isValid = await protocol.validateCode("wallet", result.actionCode, {
331
+ chain: "solana",
332
+ pubkey: "your-public-key",
333
+ signature: signature
334
+ });
335
+ ```
50
336
 
51
- ---
337
+ #### Vision
52
338
 
53
- ## 📜 License
339
+ Action Codes Protocol aim to be the OTP protocol for blockchains but allowing more than authentication: a simple, universal interaction layer usable across apps, chains, and eventually banks/CBDCs.
54
340
 
55
- This protocol is open source under the [Apache 2.0 License](./LICENSE).
@@ -0,0 +1,37 @@
1
+ import type { ActionCode, CodeGenerationConfig, DelegationCertificate, DelegatedActionCode } from "./types";
2
+ import type { ChainAdapter, ChainWalletStrategyContext } from "./adapters/BaseChainAdapter";
3
+ import { WalletStrategy } from "./strategy/WalletStrategy";
4
+ import { DelegationStrategy } from "./strategy/DelegationStrategy";
5
+ import { SolanaAdapter } from "./adapters/SolanaAdapter";
6
+ export declare class ActionCodesProtocol {
7
+ private readonly config;
8
+ private adapters;
9
+ private _walletStrategy;
10
+ private _delegationStrategy;
11
+ constructor(config: CodeGenerationConfig);
12
+ getConfig(): CodeGenerationConfig;
13
+ /** Register a chain adapter */
14
+ registerAdapter(chain: string, adapter: ChainAdapter): void;
15
+ /** Get a registered adapter */
16
+ getAdapter(chain: string): ChainAdapter | undefined;
17
+ /** Typed access to specific adapters */
18
+ get adapter(): {
19
+ solana: SolanaAdapter;
20
+ };
21
+ /** Access to strategies */
22
+ get walletStrategy(): WalletStrategy;
23
+ /** Get canonical message parts for signing (before code generation) */
24
+ getCanonicalMessageParts(pubkey: string, providedSecret?: string): Uint8Array;
25
+ get delegationStrategy(): DelegationStrategy;
26
+ createDelegationCertificateTemplate(userPublicKey: string, durationMs?: number, chain?: string): Omit<DelegationCertificate, "signature">;
27
+ generateCode(strategy: "wallet", canonicalMessage: Uint8Array, signature: string, providedSecret?: string): {
28
+ actionCode: ActionCode;
29
+ canonicalMessage: Uint8Array;
30
+ };
31
+ generateCode(strategy: "delegation", certificate: DelegationCertificate): {
32
+ actionCode: DelegatedActionCode;
33
+ };
34
+ validateCode(strategy: "wallet", actionCode: ActionCode, context?: Omit<ChainWalletStrategyContext<unknown>, "canonicalMessageParts">): void;
35
+ validateCode(strategy: "delegation", actionCode: DelegatedActionCode, certificate: DelegationCertificate): void;
36
+ }
37
+ //# sourceMappingURL=ActionCodesProtocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionCodesProtocol.d.ts","sourceRoot":"","sources":["../src/ActionCodesProtocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EACV,YAAY,EACZ,0BAA0B,EAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAsB,MAAM,0BAA0B,CAAC;AAI7E,qBAAa,mBAAmB;IAKlB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,eAAe,CAAiB;IACxC,OAAO,CAAC,mBAAmB,CAAqB;gBAEnB,MAAM,EAAE,oBAAoB;IASlD,SAAS,IAAI,oBAAoB;IAIxC,+BAA+B;IAC/B,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAI3D,+BAA+B;IAC/B,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAInD,wCAAwC;IACxC,IAAI,OAAO;gBAEoC,aAAa;MAE3D;IAED,2BAA2B;IAC3B,IAAI,cAAc,mBAEjB;IAED,uEAAuE;IACvE,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,UAAU;IAK7E,IAAI,kBAAkB,uBAErB;IAGD,mCAAmC,CACjC,aAAa,EAAE,MAAM,EACrB,UAAU,GAAE,MAAgB,EAC5B,KAAK,GAAE,MAAiB,GACvB,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC;IAS3C,YAAY,CACV,QAAQ,EAAE,QAAQ,EAClB,gBAAgB,EAAE,UAAU,EAC5B,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,GACtB;QACD,UAAU,EAAE,UAAU,CAAC;QACvB,gBAAgB,EAAE,UAAU,CAAC;KAC9B;IACD,YAAY,CACV,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,qBAAqB,GACjC;QACD,UAAU,EAAE,mBAAmB,CAAC;KACjC;IAyBD,YAAY,CACV,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,IAAI,CAAC,0BAA0B,CAAC,OAAO,CAAC,EAAE,uBAAuB,CAAC,GAC3E,IAAI;IACP,YAAY,CACV,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,mBAAmB,EAC/B,WAAW,EAAE,qBAAqB,GACjC,IAAI;CA0DR"}
@@ -0,0 +1,22 @@
1
+ import type { CanonicalMessageParts, DelegationCertificate } from "../types";
2
+ export interface BaseWalletStrategyContext {
3
+ chain: string;
4
+ canonicalMessageParts: CanonicalMessageParts;
5
+ }
6
+ export interface BaseDelegationContext {
7
+ chain: string;
8
+ pubkey: string;
9
+ signature: string;
10
+ certificate: DelegationCertificate;
11
+ }
12
+ export type ChainWalletStrategyContext<T> = BaseWalletStrategyContext & T;
13
+ export type ChainDelegationStrategyContext<T> = BaseDelegationContext & T;
14
+ export interface ChainAdapter<TCtx = unknown, DCtx = unknown> {
15
+ verifyWithWallet(context: ChainWalletStrategyContext<TCtx>): boolean;
16
+ verifyWithDelegation(context: ChainDelegationStrategyContext<DCtx>): boolean;
17
+ }
18
+ export declare abstract class BaseChainAdapter<TCtx, DCtx> implements ChainAdapter<TCtx, DCtx> {
19
+ abstract verifyWithWallet(context: ChainWalletStrategyContext<TCtx>): boolean;
20
+ abstract verifyWithDelegation(context: ChainDelegationStrategyContext<DCtx>): boolean;
21
+ }
22
+ //# sourceMappingURL=BaseChainAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseChainAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/BaseChainAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAG7E,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IAEd,qBAAqB,EAAE,qBAAqB,CAAC;CAC9C;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,qBAAqB,CAAC;CACpC;AAED,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI,yBAAyB,GAAG,CAAC,CAAC;AAC1E,MAAM,MAAM,8BAA8B,CAAC,CAAC,IAAI,qBAAqB,GAAG,CAAC,CAAC;AAC1E,MAAM,WAAW,YAAY,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,GAAG,OAAO;IAC1D,gBAAgB,CAAC,OAAO,EAAE,0BAA0B,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IACrE,oBAAoB,CAAC,OAAO,EAAE,8BAA8B,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;CAC9E;AAED,8BAAsB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAE,YAAW,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC;IACpF,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,0BAA0B,CAAC,IAAI,CAAC,GAAG,OAAO;IAC7E,QAAQ,CAAC,oBAAoB,CAAC,OAAO,EAAE,8BAA8B,CAAC,IAAI,CAAC,GAAG,OAAO;CACtF"}
@@ -0,0 +1,44 @@
1
+ import { PublicKey, Transaction, VersionedTransaction, TransactionInstruction } from "@solana/web3.js";
2
+ import { BaseChainAdapter, type ChainWalletStrategyContext, type ChainDelegationStrategyContext } from "./BaseChainAdapter";
3
+ import { type ProtocolMetaFields } from "../utils/protocolMeta";
4
+ import type { ActionCode } from "../types";
5
+ export type SolanaContext = {
6
+ pubkey: string | PublicKey;
7
+ signature: string;
8
+ };
9
+ /** Union of supported Solana txn types */
10
+ export type SolanaTransaction = Transaction | VersionedTransaction;
11
+ export declare class SolanaAdapter extends BaseChainAdapter<SolanaContext, SolanaContext> {
12
+ /** Normalize pubkey input to PublicKey */
13
+ private normalizePubkey;
14
+ /** Verify the signature over canonical message (protocol-level) */
15
+ verifyWithWallet(context: ChainWalletStrategyContext<SolanaContext>): boolean;
16
+ /** Verify delegation certificate signature */
17
+ verifyWithDelegation(context: ChainDelegationStrategyContext<SolanaContext>): boolean;
18
+ /** Create a Solana memo instruction carrying protocol meta (for SDK/clients) */
19
+ static createProtocolMetaIx(meta: ProtocolMetaFields): TransactionInstruction;
20
+ /** Extract protocol metadata string (memo) from a transaction, or null */
21
+ getProtocolMeta(tx: SolanaTransaction): string | null;
22
+ /** Get parsed ProtocolMeta object, or null if none or invalid */
23
+ parseMeta(tx: SolanaTransaction): ProtocolMetaFields | null;
24
+ /** List memo instructions from the transaction (legacy & versioned) */
25
+ private getMemoInstructions;
26
+ /**
27
+ * Validate that a transaction's memo meta aligns with the bound `actionCode`.
28
+ * Throws ProtocolError if validation fails.
29
+ */
30
+ verifyTransactionMatchesCode(actionCode: ActionCode, tx: SolanaTransaction): void;
31
+ /**
32
+ * Verify that the transaction is signed by the "intendedFor" pubkey
33
+ * as declared in the protocol meta of the transaction.
34
+ * Throws ProtocolError if validation fails.
35
+ */
36
+ verifyTransactionSignedByIntentOwner(tx: SolanaTransaction): void;
37
+ /**
38
+ * Attach protocol meta into a legacy or versioned transaction.
39
+ *
40
+ * ⚠️ Note: this mutates the given transaction.
41
+ */
42
+ static attachProtocolMeta<T extends SolanaTransaction>(tx: T, meta: ProtocolMetaFields): T;
43
+ }
44
+ //# sourceMappingURL=SolanaAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SolanaAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SolanaAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EAEvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,KAAK,0BAA0B,EAAE,KAAK,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAC5H,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAK3C,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEnE,qBAAa,aAAc,SAAQ,gBAAgB,CAAC,aAAa,EAAE,aAAa,CAAC;IAC/E,0CAA0C;IAC1C,OAAO,CAAC,eAAe;IAOvB,mEAAmE;IACnE,gBAAgB,CAAC,OAAO,EAAE,0BAA0B,CAAC,aAAa,CAAC,GAAG,OAAO;IA0B7E,8CAA8C;IAC9C,oBAAoB,CAAC,OAAO,EAAE,8BAA8B,CAAC,aAAa,CAAC,GAAG,OAAO;IAiDrF,gFAAgF;IAChF,MAAM,CAAC,oBAAoB,CACzB,IAAI,EAAE,kBAAkB,GACvB,sBAAsB;IAKzB,0EAA0E;IAC1E,eAAe,CAAC,EAAE,EAAE,iBAAiB,GAAG,MAAM,GAAG,IAAI;IAerD,iEAAiE;IACjE,SAAS,CAAC,EAAE,EAAE,iBAAiB,GAAG,kBAAkB,GAAG,IAAI;IAM3D,uEAAuE;IACvE,OAAO,CAAC,mBAAmB;IAmC3B;;;OAGG;IACH,4BAA4B,CAC1B,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,iBAAiB,GACpB,IAAI;IAiCP;;;;OAIG;IACH,oCAAoC,CAAC,EAAE,EAAE,iBAAiB,GAAG,IAAI;IAoEjE;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CAAC,CAAC,SAAS,iBAAiB,EACnD,EAAE,EAAE,CAAC,EACL,IAAI,EAAE,kBAAkB,GACvB,CAAC;CA+CL"}
@@ -1,10 +1,8 @@
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;
1
+ export declare const PROTOCOL_NORMALIZATION = "NFC";
2
+ export declare const PROTOCOL_META_MAX_BYTES = 256;
3
+ export declare const CODE_MIN_LENGTH = 6;
4
+ export declare const CODE_MAX_LENGTH = 24;
5
+ export declare const CODE_DEFAULT_LENGTH = 8;
6
+ export declare const CODE_CHARSET_DIGITS = "0123456789";
8
7
  export declare const SUPPORTED_CHAINS: readonly ["solana"];
9
- export type SupportedChain = (typeof SUPPORTED_CHAINS)[number];
10
8
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAcA,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"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAC5C,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAGrC,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAEhD,eAAO,MAAM,gBAAgB,qBAAsB,CAAC"}
@@ -0,0 +1,63 @@
1
+ export declare enum ProtocolErrorCode {
2
+ EXPIRED_CODE = "EXPIRED_CODE",
3
+ INVALID_CODE_FORMAT = "INVALID_CODE_FORMAT",
4
+ INVALID_SIGNATURE = "INVALID_SIGNATURE",
5
+ MISSING_META = "MISSING_META",
6
+ INVALID_META_FORMAT = "INVALID_META_FORMAT",
7
+ META_MISMATCH = "META_MISMATCH",
8
+ META_TOO_LARGE = "META_TOO_LARGE",
9
+ TRANSACTION_NOT_SIGNED_BY_INTENDED_OWNER = "TRANSACTION_NOT_SIGNED_BY_INTENDED_OWNER",
10
+ INVALID_TRANSACTION_FORMAT = "INVALID_TRANSACTION_FORMAT",
11
+ INVALID_PUBKEY_FORMAT = "INVALID_PUBKEY_FORMAT",
12
+ INVALID_INPUT = "INVALID_INPUT",
13
+ MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD",
14
+ CRYPTO_ERROR = "CRYPTO_ERROR",
15
+ INVALID_DIGEST = "INVALID_DIGEST",
16
+ INVALID_ADAPTER = "INVALID_ADAPTER"
17
+ }
18
+ export declare class ProtocolError extends Error {
19
+ readonly code: ProtocolErrorCode;
20
+ readonly details?: Record<string, unknown> | undefined;
21
+ constructor(code: ProtocolErrorCode, message: string, details?: Record<string, unknown> | undefined);
22
+ static expiredCode(code: string, expiresAt: number, currentTime: number): ExpiredCodeError;
23
+ static invalidCodeFormat(code: string, reason: string): InvalidCodeFormatError;
24
+ static invalidSignature(reason: string): InvalidSignatureError;
25
+ static missingMeta(): MissingMetaError;
26
+ static invalidMetaFormat(reason: string): ProtocolError;
27
+ static metaMismatch(expected: string, actual: string, field: string): MetaMismatchError;
28
+ static metaTooLarge(maxBytes: number, actualBytes: number): ProtocolError;
29
+ static transactionNotSignedByIntendedOwner(intended: string, actualSigners: string[]): TransactionNotSignedByIntendedOwnerError;
30
+ static invalidTransactionFormat(reason: string): ProtocolError;
31
+ static invalidPubkeyFormat(pubkey: string, reason: string): InvalidPubkeyFormatError;
32
+ static invalidInput(field: string, value: unknown, reason: string): ProtocolError;
33
+ static missingRequiredField(field: string): ProtocolError;
34
+ static cryptoError(operation: string, reason: string): ProtocolError;
35
+ static invalidDigest(reason: string): ProtocolError;
36
+ static invalidAdapter(adapter: string): InvalidAdapterError;
37
+ static create(code: ProtocolErrorCode, message: string, details?: Record<string, unknown>): ProtocolError;
38
+ }
39
+ export declare class ExpiredCodeError extends ProtocolError {
40
+ constructor(code: string, expiresAt: number, currentTime: number);
41
+ }
42
+ export declare class MissingMetaError extends ProtocolError {
43
+ constructor();
44
+ }
45
+ export declare class MetaMismatchError extends ProtocolError {
46
+ constructor(expected: string, actual: string, field: string);
47
+ }
48
+ export declare class TransactionNotSignedByIntendedOwnerError extends ProtocolError {
49
+ constructor(intended: string, actualSigners: string[]);
50
+ }
51
+ export declare class InvalidPubkeyFormatError extends ProtocolError {
52
+ constructor(pubkey: string, reason: string);
53
+ }
54
+ export declare class InvalidSignatureError extends ProtocolError {
55
+ constructor(reason: string);
56
+ }
57
+ export declare class InvalidCodeFormatError extends ProtocolError {
58
+ constructor(code: string, reason: string);
59
+ }
60
+ export declare class InvalidAdapterError extends ProtocolError {
61
+ constructor(adapter: string);
62
+ }
63
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}