@actioncodes/protocol 2.0.22 → 2.0.24
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/README.md +239 -146
- package/dist/adapters/SolanaAdapter.d.ts +8 -2
- package/dist/adapters/SolanaAdapter.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +3 -3
- package/docs/ActionCodesProtocol/README.md +2 -2
- package/docs/ActionCodesProtocol/classes/ActionCodesProtocol.md +183 -33
- package/docs/README.md +425 -8
- package/docs/adapters/BaseChainAdapter/README.md +3 -4
- package/docs/adapters/BaseChainAdapter/classes/BaseChainAdapter.md +87 -20
- package/docs/adapters/BaseChainAdapter/interfaces/ChainAdapter.md +68 -12
- package/docs/adapters/BaseChainAdapter/type-aliases/SignFn.md +25 -0
- package/docs/adapters/SolanaAdapter/README.md +6 -3
- package/docs/adapters/SolanaAdapter/classes/SolanaAdapter.md +140 -43
- package/docs/adapters/SolanaAdapter/type-aliases/SolanaTransaction.md +3 -3
- package/docs/adapters/SolanaAdapter/variables/ADAPTER_CHAIN_NAME.md +11 -0
- package/docs/constants/README.md +2 -2
- package/docs/constants/variables/CODE_CHARSET_DIGITS.md +2 -2
- package/docs/constants/variables/CODE_DEFAULT_LENGTH.md +2 -2
- package/docs/constants/variables/CODE_MAX_LENGTH.md +2 -2
- package/docs/constants/variables/CODE_MIN_LENGTH.md +2 -2
- package/docs/constants/variables/PROTOCOL_META_MAX_BYTES.md +3 -3
- package/docs/constants/variables/PROTOCOL_NORMALIZATION.md +2 -2
- package/docs/constants/variables/SUPPORTED_CHAINS.md +9 -3
- package/docs/errors/README.md +4 -2
- package/docs/errors/classes/ExpiredCodeError.md +85 -21
- package/docs/errors/classes/InvalidAdapterError.md +751 -0
- package/docs/errors/classes/InvalidCodeFormatError.md +85 -21
- package/docs/errors/classes/InvalidPubkeyFormatError.md +85 -21
- package/docs/errors/classes/InvalidSignatureError.md +85 -21
- package/docs/errors/classes/MetaMismatchError.md +85 -21
- package/docs/errors/classes/MissingMetaError.md +85 -21
- package/docs/errors/classes/ProtocolError.md +75 -21
- package/docs/errors/classes/TransactionNotSignedByIntendedOwnerError.md +85 -21
- package/docs/errors/classes/TransactionNotSignedByIssuerError.md +755 -0
- package/docs/errors/enumerations/ProtocolErrorCode.md +39 -15
- package/docs/index/README.md +170 -14
- package/docs/modules.md +3 -3
- package/docs/strategy/DelegationStrategy/README.md +11 -0
- package/docs/strategy/DelegationStrategy/classes/DelegationStrategy.md +79 -0
- package/docs/strategy/WalletStrategy/README.md +2 -2
- package/docs/strategy/WalletStrategy/classes/WalletStrategy.md +22 -18
- package/docs/types/README.md +11 -3
- package/docs/types/interfaces/ActionCode.md +23 -26
- package/docs/types/interfaces/ActionCodeRevoke.md +93 -0
- package/docs/types/interfaces/CanonicalMessageParts.md +5 -13
- package/docs/types/interfaces/CanonicalRevokeMessageParts.md +33 -0
- package/docs/types/interfaces/CodeGenerationConfig.md +6 -6
- package/docs/types/interfaces/DelegatedActionCode.md +97 -0
- package/docs/types/interfaces/DelegatedActionCodeRevoke.md +105 -0
- package/docs/types/interfaces/DelegationProof.md +49 -0
- package/docs/types/type-aliases/Chain.md +11 -0
- package/docs/utils/canonical/README.md +6 -2
- package/docs/utils/canonical/functions/getCanonicalMessageParts.md +21 -0
- package/docs/utils/canonical/functions/serializeCanonical.md +3 -3
- package/docs/utils/canonical/functions/serializeCanonicalRevoke.md +21 -0
- package/docs/utils/canonical/functions/serializeDelegationProof.md +21 -0
- package/docs/utils/canonical/variables/CANONICAL_MESSAGE_PREFIX.md +3 -3
- package/docs/utils/canonical/variables/CANONICAL_MESSAGE_VERSION.md +3 -3
- package/docs/utils/canonical/variables/CANONICAL_REVOKE_MESSAGE_PREFIX.md +11 -0
- package/docs/utils/crypto/README.md +2 -3
- package/docs/utils/crypto/functions/base32EncodeCrockford.md +2 -2
- package/docs/utils/crypto/functions/codeHash.md +2 -2
- package/docs/utils/crypto/functions/digestToDigits.md +2 -2
- package/docs/utils/crypto/functions/hkdfSha256.md +2 -2
- package/docs/utils/crypto/functions/hmacSha256.md +2 -2
- package/docs/utils/crypto/functions/sha256.md +2 -2
- package/docs/utils/crypto/functions/truncateBits.md +2 -2
- package/docs/utils/protocolMeta/README.md +2 -2
- package/docs/utils/protocolMeta/functions/buildProtocolMeta.md +3 -3
- package/docs/utils/protocolMeta/functions/parseProtocolMeta.md +3 -3
- package/docs/utils/protocolMeta/functions/validateProtocolMetaFormat.md +3 -3
- package/docs/utils/protocolMeta/interfaces/ProtocolMetaFields.md +11 -3
- package/docs/utils/protocolMeta/variables/SCHEME.md +3 -3
- package/package.json +7 -7
- package/docs/adapters/BaseChainAdapter/interfaces/BaseContext.md +0 -17
- package/docs/adapters/BaseChainAdapter/type-aliases/ChainContext.md +0 -23
- package/docs/adapters/NodeCryptoAdapter/README.md +0 -15
- package/docs/adapters/NodeCryptoAdapter/classes/NodeCryptoAdapter.md +0 -254
- package/docs/adapters/NodeCryptoAdapter/type-aliases/NodeCryptoContext.md +0 -27
- package/docs/adapters/SolanaAdapter/type-aliases/SolanaContext.md +0 -27
- package/docs/types/interfaces/CodeGenerationResult.md +0 -25
- package/docs/utils/crypto/functions/generateRandomSecret.md +0 -15
package/docs/README.md
CHANGED
|
@@ -1,19 +1,436 @@
|
|
|
1
|
-
**@actioncodes/protocol
|
|
1
|
+
**@actioncodes/protocol**
|
|
2
2
|
|
|
3
3
|
***
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Action Codes Protocol
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
The Action Codes Protocol is a lightweight way to prove intent and authorize actions across blockchains, apps, and wallets.
|
|
8
|
+
Instead of heavy signature popups or complex flows, it uses short-lived one-time codes derived from canonical cryptographic messages.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
### This enables:
|
|
11
|
+
- Secure intent binding – the code is cryptographically tied to a wallet/public key.
|
|
12
|
+
- Fast verification – relayers/servers can validate in microseconds (~3ms per verification).
|
|
13
|
+
- Cross-chain support – adapters handle chain-specific quirks (currently supporting Solana)
|
|
14
|
+
- Simple dev UX – just generate → sign → verify.
|
|
15
|
+
- Issuer support – allows separation between code issuer and intent owner for advanced use cases.
|
|
16
|
+
|
|
17
|
+
### What's new in v2 (compared to [v1](https://github.com/otaprotocol/actioncodes))
|
|
18
|
+
- Now we use Bun as core library. We are down to ~3ms per code signature verification on commodity hardware.
|
|
19
|
+
- Canonical Messages only → No ambiguity. Codes are always derived from a canonical serialization (serializeCanonical).
|
|
20
|
+
- No AIPs (Action Codes Improvement Proposals) → Overkill for lightweight protocol.
|
|
21
|
+
- Chain Adapters simplified → They don't enforce business rules; they just provide utilities:
|
|
22
|
+
- createProtocolMetaIx (for attaching metadata)
|
|
23
|
+
- parseMeta / verifyTransactionMatchesCode (for checking integrity)
|
|
24
|
+
- verifyTransactionSignedByIntentOwner (checks both `int` and `iss` signatures when present).
|
|
25
|
+
- Errors are typed → Clear ProtocolError.* categories instead of generic fails.
|
|
26
|
+
|
|
27
|
+
### Core Concepts
|
|
28
|
+
|
|
29
|
+
1. Action Codes
|
|
30
|
+
- A short-lived, one-time code bound to a wallet/public key.
|
|
31
|
+
- Generated using HMAC/HKDF and canonical serialization.
|
|
32
|
+
|
|
33
|
+
2. Protocol Meta
|
|
34
|
+
- The "payload" carried with transactions to tie them to action codes.
|
|
35
|
+
- Versioned, deterministic, size-limited (max 512 bytes).
|
|
36
|
+
- Fields: `ver` (version), `id` (code hash), `int` (intent owner), `iss` (issuer, optional), `p` (params, optional).
|
|
37
|
+
- When `iss` field is present, both issuer and intent owner must sign the transaction.
|
|
38
|
+
- Perfect for attaching to transactions or off-chain messages for tracing.
|
|
39
|
+
|
|
40
|
+
3. Canonical Message
|
|
41
|
+
- A deterministic JSON serialization of (pubkey, code, timestamp, optional secret)
|
|
42
|
+
- Always signed by the user's wallet.
|
|
43
|
+
- Prevents replay / tampering.
|
|
44
|
+
|
|
45
|
+
## Strategy Architecture
|
|
46
|
+
|
|
47
|
+
The Action Codes Protocol supports two main strategies for generating and validating codes:
|
|
48
|
+
|
|
49
|
+
### 1. Wallet Strategy (Direct)
|
|
50
|
+
|
|
51
|
+
The **Wallet Strategy** is the simplest approach where codes are generated directly from a user's wallet.
|
|
52
|
+
|
|
53
|
+
#### How it works:
|
|
54
|
+
```typescript
|
|
55
|
+
import { ActionCodesProtocol } from '@actioncodes/protocol';
|
|
56
|
+
import { SolanaAdapter } from '@actioncodes/protocol';
|
|
57
|
+
|
|
58
|
+
// Initialize protocol
|
|
59
|
+
const protocol = new ActionCodesProtocol({
|
|
60
|
+
codeLength: 8, // Code length (6-24 digits)
|
|
61
|
+
ttlMs: 120000, // Time to live (2 minutes)
|
|
62
|
+
clockSkewMs: 5000 // Clock skew tolerance (5 seconds)
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Register Solana adapter
|
|
66
|
+
protocol.registerAdapter('solana', new SolanaAdapter());
|
|
67
|
+
|
|
68
|
+
// 1. Generate code with wallet strategy
|
|
69
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
70
|
+
// Sign the canonical message with user's wallet
|
|
71
|
+
const signature = await userWallet.signMessage(message);
|
|
72
|
+
return signature; // Returns base58-encoded signature
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const actionCode = await protocol.generate(
|
|
76
|
+
"wallet",
|
|
77
|
+
userWallet.publicKey.toString(),
|
|
78
|
+
"solana",
|
|
79
|
+
signFn
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// 2. Validate code
|
|
83
|
+
protocol.validate("wallet", actionCode);
|
|
84
|
+
// Throws ProtocolError if validation fails
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### Key Features:
|
|
88
|
+
- **Signature-based security** - Codes require a valid signature over the canonical message (prevents public key + timestamp attacks)
|
|
89
|
+
- **Direct wallet binding** - Codes are cryptographically tied to the user's public key
|
|
90
|
+
- **HMAC-based generation** - Uses signature as entropy source for secure code generation
|
|
91
|
+
- **Immediate validation** - No delegation certificates needed
|
|
92
|
+
- **Perfect for** - Direct user interactions, simple authentication flows, transaction authorization
|
|
93
|
+
|
|
94
|
+
#### Security Model:
|
|
95
|
+
- **Signature verification** - All codes require a valid signature over the canonical message
|
|
96
|
+
- **Public key + timestamp attack prevention** - Signatures prevent attackers from generating codes with just public key + timestamp
|
|
97
|
+
- **HMAC-based entropy** - Codes use HMAC-SHA256 with signature as key, ensuring cryptographic security
|
|
98
|
+
- Codes are bound to the specific public key and timestamp
|
|
99
|
+
- Time-based expiration prevents replay attacks
|
|
100
|
+
- Canonical message signing ensures integrity
|
|
101
|
+
|
|
102
|
+
### 2. Delegation Strategy (Advanced)
|
|
103
|
+
|
|
104
|
+
The **Delegation Strategy** allows users to pre-authorize actions through delegation proofs, enabling more complex workflows like relayer services.
|
|
105
|
+
|
|
106
|
+
#### How it works:
|
|
107
|
+
|
|
108
|
+
##### Step 1: Create Delegation Proof
|
|
109
|
+
```typescript
|
|
110
|
+
import { serializeDelegationProof } from '@actioncodes/protocol';
|
|
111
|
+
|
|
112
|
+
// User creates a delegation proof
|
|
113
|
+
const delegationProof = {
|
|
114
|
+
walletPubkey: userWallet.publicKey.toString(),
|
|
115
|
+
delegatedPubkey: delegatedKeypair.publicKey.toString(),
|
|
116
|
+
chain: "solana",
|
|
117
|
+
expiresAt: Date.now() + 3600000, // 1 hour expiration
|
|
118
|
+
signature: "" // Will be set after signing
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// User signs the delegation proof
|
|
122
|
+
const delegationMessage = serializeDelegationProof(delegationProof);
|
|
123
|
+
const delegationSignature = await userWallet.signMessage(delegationMessage);
|
|
124
|
+
delegationProof.signature = delegationSignature;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
##### Step 2: Generate Delegated Codes
|
|
128
|
+
```typescript
|
|
129
|
+
// Sign function for delegated keypair
|
|
130
|
+
const delegatedSignFn = async (message: Uint8Array, chain: string) => {
|
|
131
|
+
const signature = await delegatedKeypair.signMessage(message);
|
|
132
|
+
return signature;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Generate code using delegation strategy
|
|
136
|
+
const delegatedActionCode = await protocol.generate(
|
|
137
|
+
"delegation",
|
|
138
|
+
delegationProof,
|
|
139
|
+
"solana",
|
|
140
|
+
delegatedSignFn
|
|
141
|
+
);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
##### Step 3: Validate Delegated Codes
|
|
145
|
+
```typescript
|
|
146
|
+
// Validate the delegated code
|
|
147
|
+
protocol.validate("delegation", delegatedActionCode);
|
|
148
|
+
// Throws ProtocolError if validation fails
|
|
11
149
|
```
|
|
12
150
|
|
|
13
|
-
|
|
151
|
+
#### Key Features:
|
|
152
|
+
- **Pre-authorization** - Users can authorize actions for a limited time
|
|
153
|
+
- **Relayer support** - Third parties can validate codes without generating them
|
|
154
|
+
- **Proof-based** - Codes are bound to specific delegation proofs
|
|
155
|
+
- **Time-limited** - Delegation proofs have expiration times
|
|
156
|
+
- **Perfect for** - Relayer services, automated systems, complex workflows
|
|
157
|
+
|
|
158
|
+
#### Security Model:
|
|
159
|
+
- **Code-Proof Binding** - Codes are cryptographically bound to their specific delegation proof
|
|
160
|
+
- **Signature Verification** - Delegation proof signatures are verified using chain adapters
|
|
161
|
+
- **Dual Signature Requirement** - Both wallet signature (on proof) and delegated signature (on code) are required
|
|
162
|
+
- **Cross-Proof Protection** - Codes from one delegation proof cannot be used with another
|
|
163
|
+
- **Relayer Security** - Relayers can validate codes but cannot generate them without the delegated keypair's signature
|
|
164
|
+
|
|
165
|
+
#### Important Security Guarantees:
|
|
166
|
+
|
|
167
|
+
1. **Stolen Delegation Proofs are Limited**
|
|
168
|
+
- Delegation proofs contain public data (pubkeys, expiration, chain)
|
|
169
|
+
- They cannot be used to generate codes without the delegated keypair's private key
|
|
170
|
+
- The proof signature prevents tampering but doesn't enable code generation
|
|
171
|
+
|
|
172
|
+
2. **Stolen Signatures Cannot Create Valid Codes**
|
|
173
|
+
- Even if an attacker steals a signature, they cannot create valid codes
|
|
174
|
+
- Codes are bound to the ENTIRE delegation proof (not just the signature)
|
|
175
|
+
- Different proof data = different code = validation failure
|
|
176
|
+
|
|
177
|
+
3. **Relayer Code Generation Prevention**
|
|
178
|
+
- Relayers cannot generate codes even with public delegation proof data
|
|
179
|
+
- Codes require signatures from the delegated keypair (private asset)
|
|
180
|
+
- Only holders of the delegated keypair can generate valid codes
|
|
181
|
+
|
|
182
|
+
4. **Code-Proof Binding**
|
|
183
|
+
- Codes are cryptographically linked to their specific delegation proof
|
|
184
|
+
- Cross-proof attacks are impossible
|
|
185
|
+
- Each delegation proof produces unique codes
|
|
186
|
+
|
|
187
|
+
#### Delegation Proof Structure:
|
|
188
|
+
```typescript
|
|
189
|
+
interface DelegationProof {
|
|
190
|
+
walletPubkey: string; // Original wallet's public key
|
|
191
|
+
delegatedPubkey: string; // Delegated keypair's public key
|
|
192
|
+
chain: string; // Target blockchain
|
|
193
|
+
expiresAt: number; // Expiration timestamp
|
|
194
|
+
signature: string; // Wallet's signature of the delegation proof
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### Delegated Action Code Structure:
|
|
199
|
+
```typescript
|
|
200
|
+
interface DelegatedActionCode {
|
|
201
|
+
code: string; // The actual action code
|
|
202
|
+
pubkey: string; // Delegated pubkey (who signs the code)
|
|
203
|
+
timestamp: number; // Generation timestamp
|
|
204
|
+
expiresAt: number; // Code expiration
|
|
205
|
+
signature: string; // Signature from delegated keypair
|
|
206
|
+
chain: string; // Target blockchain
|
|
207
|
+
delegationProof: DelegationProof; // The delegation proof
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Use Cases & Examples
|
|
212
|
+
|
|
213
|
+
### Wallet Strategy Use Cases
|
|
214
|
+
|
|
215
|
+
#### 1. Simple Authentication
|
|
216
|
+
```typescript
|
|
217
|
+
// User logs into a dApp
|
|
218
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
219
|
+
return await userWallet.signMessage(message);
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const actionCode = await protocol.generate(
|
|
223
|
+
"wallet",
|
|
224
|
+
userWallet.publicKey.toString(),
|
|
225
|
+
"solana",
|
|
226
|
+
signFn
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// dApp validates the code
|
|
230
|
+
protocol.validate("wallet", actionCode);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
#### 2. Transaction Authorization
|
|
234
|
+
```typescript
|
|
235
|
+
import { buildProtocolMeta, codeHash } from '@actioncodes/protocol';
|
|
236
|
+
|
|
237
|
+
// User authorizes a specific transaction
|
|
238
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
239
|
+
return await userWallet.signMessage(message);
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const actionCode = await protocol.generate(
|
|
243
|
+
"wallet",
|
|
244
|
+
userWallet.publicKey.toString(),
|
|
245
|
+
"solana",
|
|
246
|
+
signFn
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
// Relayer validates before executing
|
|
250
|
+
protocol.validate("wallet", actionCode);
|
|
251
|
+
|
|
252
|
+
// Attach protocol meta to transaction
|
|
253
|
+
const adapter = protocol.getAdapter("solana") as SolanaAdapter;
|
|
254
|
+
const meta = buildProtocolMeta({
|
|
255
|
+
ver: 2,
|
|
256
|
+
id: codeHash(actionCode.code),
|
|
257
|
+
int: actionCode.pubkey,
|
|
258
|
+
});
|
|
259
|
+
const txWithMeta = SolanaAdapter.attachProtocolMeta(transactionBase64, meta);
|
|
260
|
+
|
|
261
|
+
// Verify transaction is signed by the intended owner
|
|
262
|
+
adapter.verifyTransactionSignedByIntentOwner(txWithMeta);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Delegation Strategy Use Cases
|
|
266
|
+
|
|
267
|
+
#### 1. Relayer Services
|
|
268
|
+
```typescript
|
|
269
|
+
// User creates delegation proof for relayer
|
|
270
|
+
const delegationProof = {
|
|
271
|
+
walletPubkey: userWallet.publicKey.toString(),
|
|
272
|
+
delegatedPubkey: relayerKeypair.publicKey.toString(),
|
|
273
|
+
chain: "solana",
|
|
274
|
+
expiresAt: Date.now() + 3600000, // 1 hour
|
|
275
|
+
signature: await signDelegationProof(delegationProof)
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
// Relayer can validate codes but not generate them
|
|
279
|
+
// User generates codes that relayer can validate
|
|
280
|
+
const delegatedSignFn = async (message: Uint8Array, chain: string) => {
|
|
281
|
+
return await relayerKeypair.signMessage(message);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const actionCode = await protocol.generate(
|
|
285
|
+
"delegation",
|
|
286
|
+
delegationProof,
|
|
287
|
+
"solana",
|
|
288
|
+
delegatedSignFn
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
// Relayer validates the code
|
|
292
|
+
protocol.validate("delegation", actionCode);
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
#### 2. Automated Trading Bots
|
|
296
|
+
```typescript
|
|
297
|
+
// User authorizes trading bot for 24 hours
|
|
298
|
+
const delegationProof = {
|
|
299
|
+
walletPubkey: userWallet.publicKey.toString(),
|
|
300
|
+
delegatedPubkey: botKeypair.publicKey.toString(),
|
|
301
|
+
chain: "solana",
|
|
302
|
+
expiresAt: Date.now() + 86400000, // 24 hours
|
|
303
|
+
signature: await signDelegationProof(delegationProof)
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// Bot generates codes using delegated keypair
|
|
307
|
+
const botSignFn = async (message: Uint8Array, chain: string) => {
|
|
308
|
+
return await botKeypair.signMessage(message);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const tradeCode = await protocol.generate(
|
|
312
|
+
"delegation",
|
|
313
|
+
delegationProof,
|
|
314
|
+
"solana",
|
|
315
|
+
botSignFn
|
|
316
|
+
);
|
|
317
|
+
// Bot executes trade with this code
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Security Considerations
|
|
321
|
+
|
|
322
|
+
### What Makes Action Codes Secure?
|
|
323
|
+
|
|
324
|
+
1. **Cryptographic Binding**
|
|
325
|
+
- Codes are mathematically tied to specific public keys
|
|
326
|
+
- Impossible to forge without the private key
|
|
327
|
+
|
|
328
|
+
2. **Time-Limited Validity**
|
|
329
|
+
- Codes expire automatically
|
|
330
|
+
- Prevents replay attacks
|
|
331
|
+
|
|
332
|
+
3. **One-Time Use**
|
|
333
|
+
- Each code is unique and time-bound
|
|
334
|
+
- Cannot be reused
|
|
335
|
+
|
|
336
|
+
4. **Delegation Security**
|
|
337
|
+
- Delegation proofs are cryptographically signed
|
|
338
|
+
- Codes are bound to specific delegation proofs
|
|
339
|
+
- Cross-proof attacks are impossible
|
|
340
|
+
|
|
341
|
+
### Best Practices
|
|
342
|
+
|
|
343
|
+
1. **Delegation Proof Expiration**
|
|
344
|
+
- Set appropriate expiration times for delegation proofs
|
|
345
|
+
- Shorter expiration = higher security
|
|
346
|
+
- Longer expiration = better UX
|
|
347
|
+
|
|
348
|
+
2. **Relayer Security**
|
|
349
|
+
- Only trust relayers with valid delegation proofs
|
|
350
|
+
- Never share private keys with relayers
|
|
351
|
+
- Monitor relayer behavior
|
|
352
|
+
|
|
353
|
+
3. **Issuer Field Usage**
|
|
354
|
+
- Use `iss` field when issuer and intent owner are different entities
|
|
355
|
+
- Ensure both signatures are present when `iss` is specified
|
|
356
|
+
- Omit `iss` when it's the same as `int` to save space
|
|
357
|
+
|
|
358
|
+
4. **Code Validation**
|
|
359
|
+
- Always validate codes server-side
|
|
360
|
+
- Check expiration times
|
|
361
|
+
- Verify the binding to the correct public key
|
|
362
|
+
|
|
363
|
+
5. **Protocol Meta with Issuer**
|
|
364
|
+
- Use `iss` field when issuer differs from intent owner
|
|
365
|
+
- When `iss` is present, ensure transaction is signed by both
|
|
366
|
+
- If `iss` equals `int`, it's automatically omitted (optimization)
|
|
367
|
+
|
|
368
|
+
## Performance
|
|
369
|
+
|
|
370
|
+
- **Code Generation**: ~1ms per code
|
|
371
|
+
- **Code Validation**: ~3ms per validation
|
|
372
|
+
- **Memory Usage**: Minimal (no state storage required)
|
|
373
|
+
- **Network**: No network calls required for validation
|
|
374
|
+
|
|
375
|
+
## Getting Started
|
|
14
376
|
|
|
15
377
|
```bash
|
|
16
|
-
|
|
378
|
+
# Install
|
|
379
|
+
npm install @actioncodes/protocol
|
|
380
|
+
|
|
381
|
+
# Basic usage
|
|
382
|
+
import { ActionCodesProtocol } from '@actioncodes/protocol';
|
|
383
|
+
import { SolanaAdapter } from '@actioncodes/protocol';
|
|
384
|
+
|
|
385
|
+
// Initialize protocol
|
|
386
|
+
const protocol = new ActionCodesProtocol({
|
|
387
|
+
codeLength: 8, // Code length (6-24 digits)
|
|
388
|
+
ttlMs: 120000, // Time to live (2 minutes)
|
|
389
|
+
clockSkewMs: 5000 // Clock skew tolerance (5 seconds)
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Register Solana adapter
|
|
393
|
+
protocol.registerAdapter('solana', new SolanaAdapter());
|
|
394
|
+
|
|
395
|
+
// 1. Sign function for wallet
|
|
396
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
397
|
+
// Sign the canonical message with your wallet
|
|
398
|
+
const signature = await yourWallet.signMessage(message);
|
|
399
|
+
return signature; // Returns base58-encoded signature
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// 2. Generate a code
|
|
403
|
+
const actionCode = await protocol.generate(
|
|
404
|
+
"wallet",
|
|
405
|
+
yourWallet.publicKey.toString(),
|
|
406
|
+
"solana",
|
|
407
|
+
signFn
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
// 3. Validate a code
|
|
411
|
+
protocol.validate("wallet", actionCode);
|
|
412
|
+
// Throws ProtocolError if validation fails
|
|
17
413
|
```
|
|
18
414
|
|
|
19
|
-
|
|
415
|
+
### Protocol Meta with Issuer Field
|
|
416
|
+
|
|
417
|
+
When you need to separate the issuer (who created the code) from the intent owner (who will use it):
|
|
418
|
+
|
|
419
|
+
```typescript
|
|
420
|
+
import { buildProtocolMeta } from '@actioncodes/protocol';
|
|
421
|
+
|
|
422
|
+
// Create protocol meta with issuer
|
|
423
|
+
const meta = buildProtocolMeta({
|
|
424
|
+
ver: 2,
|
|
425
|
+
id: codeHash(actionCode.code),
|
|
426
|
+
int: intentOwnerPubkey, // Who will use the code
|
|
427
|
+
iss: issuerPubkey, // Who issued the code (optional)
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// If iss is same as int, it's automatically omitted to save space
|
|
431
|
+
// If iss is present, transaction must be signed by BOTH int and iss
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
#### Vision
|
|
435
|
+
|
|
436
|
+
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 interacting with blockchains.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
[**@actioncodes/protocol
|
|
1
|
+
[**@actioncodes/protocol**](../../README.md)
|
|
2
2
|
|
|
3
3
|
***
|
|
4
4
|
|
|
5
|
-
[@actioncodes/protocol
|
|
5
|
+
[@actioncodes/protocol](../../modules.md) / adapters/BaseChainAdapter
|
|
6
6
|
|
|
7
7
|
# adapters/BaseChainAdapter
|
|
8
8
|
|
|
@@ -12,9 +12,8 @@
|
|
|
12
12
|
|
|
13
13
|
## Interfaces
|
|
14
14
|
|
|
15
|
-
- [BaseContext](interfaces/BaseContext.md)
|
|
16
15
|
- [ChainAdapter](interfaces/ChainAdapter.md)
|
|
17
16
|
|
|
18
17
|
## Type Aliases
|
|
19
18
|
|
|
20
|
-
- [
|
|
19
|
+
- [SignFn](type-aliases/SignFn.md)
|
|
@@ -1,51 +1,118 @@
|
|
|
1
|
-
[**@actioncodes/protocol
|
|
1
|
+
[**@actioncodes/protocol**](../../../README.md)
|
|
2
2
|
|
|
3
3
|
***
|
|
4
4
|
|
|
5
|
-
[@actioncodes/protocol
|
|
5
|
+
[@actioncodes/protocol](../../../modules.md) / [adapters/BaseChainAdapter](../README.md) / BaseChainAdapter
|
|
6
6
|
|
|
7
|
-
# Abstract Class: BaseChainAdapter
|
|
7
|
+
# Abstract Class: BaseChainAdapter
|
|
8
8
|
|
|
9
|
-
Defined in: src/adapters/BaseChainAdapter.ts:
|
|
9
|
+
Defined in: src/adapters/BaseChainAdapter.ts:18
|
|
10
10
|
|
|
11
11
|
## Extended by
|
|
12
12
|
|
|
13
|
-
- [`NodeCryptoAdapter`](../../NodeCryptoAdapter/classes/NodeCryptoAdapter.md)
|
|
14
13
|
- [`SolanaAdapter`](../../SolanaAdapter/classes/SolanaAdapter.md)
|
|
15
14
|
|
|
16
|
-
## Type Parameters
|
|
17
|
-
|
|
18
|
-
### TCtx
|
|
19
|
-
|
|
20
|
-
`TCtx`
|
|
21
|
-
|
|
22
15
|
## Implements
|
|
23
16
|
|
|
24
|
-
- [`ChainAdapter`](../interfaces/ChainAdapter.md)
|
|
17
|
+
- [`ChainAdapter`](../interfaces/ChainAdapter.md)
|
|
25
18
|
|
|
26
19
|
## Constructors
|
|
27
20
|
|
|
28
21
|
### Constructor
|
|
29
22
|
|
|
30
|
-
> **new BaseChainAdapter
|
|
23
|
+
> **new BaseChainAdapter**(): `BaseChainAdapter`
|
|
31
24
|
|
|
32
25
|
#### Returns
|
|
33
26
|
|
|
34
|
-
`BaseChainAdapter
|
|
27
|
+
`BaseChainAdapter`
|
|
35
28
|
|
|
36
29
|
## Methods
|
|
37
30
|
|
|
38
|
-
###
|
|
31
|
+
### verifyRevokeWithDelegation()
|
|
32
|
+
|
|
33
|
+
> `abstract` **verifyRevokeWithDelegation**(`actionCode`, `revokeSignature`): `boolean`
|
|
34
|
+
|
|
35
|
+
Defined in: src/adapters/BaseChainAdapter.ts:25
|
|
36
|
+
|
|
37
|
+
#### Parameters
|
|
38
|
+
|
|
39
|
+
##### actionCode
|
|
40
|
+
|
|
41
|
+
[`DelegatedActionCode`](../../../types/interfaces/DelegatedActionCode.md)
|
|
42
|
+
|
|
43
|
+
##### revokeSignature
|
|
44
|
+
|
|
45
|
+
`string`
|
|
46
|
+
|
|
47
|
+
#### Returns
|
|
48
|
+
|
|
49
|
+
`boolean`
|
|
50
|
+
|
|
51
|
+
#### Implementation of
|
|
52
|
+
|
|
53
|
+
[`ChainAdapter`](../interfaces/ChainAdapter.md).[`verifyRevokeWithDelegation`](../interfaces/ChainAdapter.md#verifyrevokewithdelegation)
|
|
54
|
+
|
|
55
|
+
***
|
|
56
|
+
|
|
57
|
+
### verifyRevokeWithWallet()
|
|
58
|
+
|
|
59
|
+
> `abstract` **verifyRevokeWithWallet**(`actionCode`, `revokeSignature`): `boolean`
|
|
60
|
+
|
|
61
|
+
Defined in: src/adapters/BaseChainAdapter.ts:21
|
|
62
|
+
|
|
63
|
+
#### Parameters
|
|
64
|
+
|
|
65
|
+
##### actionCode
|
|
66
|
+
|
|
67
|
+
[`ActionCode`](../../../types/interfaces/ActionCode.md)
|
|
68
|
+
|
|
69
|
+
##### revokeSignature
|
|
70
|
+
|
|
71
|
+
`string`
|
|
72
|
+
|
|
73
|
+
#### Returns
|
|
74
|
+
|
|
75
|
+
`boolean`
|
|
76
|
+
|
|
77
|
+
#### Implementation of
|
|
78
|
+
|
|
79
|
+
[`ChainAdapter`](../interfaces/ChainAdapter.md).[`verifyRevokeWithWallet`](../interfaces/ChainAdapter.md#verifyrevokewithwallet)
|
|
80
|
+
|
|
81
|
+
***
|
|
82
|
+
|
|
83
|
+
### verifyWithDelegation()
|
|
84
|
+
|
|
85
|
+
> `abstract` **verifyWithDelegation**(`actionCode`): `boolean`
|
|
86
|
+
|
|
87
|
+
Defined in: src/adapters/BaseChainAdapter.ts:20
|
|
88
|
+
|
|
89
|
+
#### Parameters
|
|
90
|
+
|
|
91
|
+
##### actionCode
|
|
92
|
+
|
|
93
|
+
[`DelegatedActionCode`](../../../types/interfaces/DelegatedActionCode.md)
|
|
94
|
+
|
|
95
|
+
#### Returns
|
|
96
|
+
|
|
97
|
+
`boolean`
|
|
98
|
+
|
|
99
|
+
#### Implementation of
|
|
100
|
+
|
|
101
|
+
[`ChainAdapter`](../interfaces/ChainAdapter.md).[`verifyWithDelegation`](../interfaces/ChainAdapter.md#verifywithdelegation)
|
|
102
|
+
|
|
103
|
+
***
|
|
104
|
+
|
|
105
|
+
### verifyWithWallet()
|
|
39
106
|
|
|
40
|
-
> `abstract` **
|
|
107
|
+
> `abstract` **verifyWithWallet**(`actionCode`): `boolean`
|
|
41
108
|
|
|
42
|
-
Defined in: src/adapters/BaseChainAdapter.ts:
|
|
109
|
+
Defined in: src/adapters/BaseChainAdapter.ts:19
|
|
43
110
|
|
|
44
111
|
#### Parameters
|
|
45
112
|
|
|
46
|
-
#####
|
|
113
|
+
##### actionCode
|
|
47
114
|
|
|
48
|
-
[`
|
|
115
|
+
[`ActionCode`](../../../types/interfaces/ActionCode.md)
|
|
49
116
|
|
|
50
117
|
#### Returns
|
|
51
118
|
|
|
@@ -53,4 +120,4 @@ Defined in: src/adapters/BaseChainAdapter.ts:15
|
|
|
53
120
|
|
|
54
121
|
#### Implementation of
|
|
55
122
|
|
|
56
|
-
[`ChainAdapter`](../interfaces/ChainAdapter.md).[`
|
|
123
|
+
[`ChainAdapter`](../interfaces/ChainAdapter.md).[`verifyWithWallet`](../interfaces/ChainAdapter.md#verifywithwallet)
|