@actioncodes/protocol 2.0.21 → 2.0.23
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.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/errors.d.ts +5 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +6 -6
- package/dist/index.js +2 -2
- package/dist/index.js.map +6 -6
- package/dist/utils/protocolMeta.d.ts +1 -0
- package/dist/utils/protocolMeta.d.ts.map +1 -1
- 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/README.md
CHANGED
|
@@ -5,9 +5,10 @@ Instead of heavy signature popups or complex flows, it uses short-lived one-time
|
|
|
5
5
|
|
|
6
6
|
### This enables:
|
|
7
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
|
|
8
|
+
- Fast verification – relayers/servers can validate in microseconds (~3ms per verification).
|
|
9
|
+
- Cross-chain support – adapters handle chain-specific quirks (currently supporting Solana)
|
|
10
10
|
- Simple dev UX – just generate → sign → verify.
|
|
11
|
+
- Issuer support – allows separation between code issuer and intent owner for advanced use cases.
|
|
11
12
|
|
|
12
13
|
### What's new in v2 (compared to [v1](https://github.com/otaprotocol/actioncodes))
|
|
13
14
|
- Now we use Bun as core library. We are down to ~3ms per code signature verification on commodity hardware.
|
|
@@ -16,7 +17,7 @@ Instead of heavy signature popups or complex flows, it uses short-lived one-time
|
|
|
16
17
|
- Chain Adapters simplified → They don't enforce business rules; they just provide utilities:
|
|
17
18
|
- createProtocolMetaIx (for attaching metadata)
|
|
18
19
|
- parseMeta / verifyTransactionMatchesCode (for checking integrity)
|
|
19
|
-
- verifyTransactionSignedByIntentOwner (
|
|
20
|
+
- verifyTransactionSignedByIntentOwner (checks both `int` and `iss` signatures when present).
|
|
20
21
|
- Errors are typed → Clear ProtocolError.* categories instead of generic fails.
|
|
21
22
|
|
|
22
23
|
### Core Concepts
|
|
@@ -27,7 +28,9 @@ Instead of heavy signature popups or complex flows, it uses short-lived one-time
|
|
|
27
28
|
|
|
28
29
|
2. Protocol Meta
|
|
29
30
|
- The "payload" carried with transactions to tie them to action codes.
|
|
30
|
-
- Versioned, deterministic, size-limited.
|
|
31
|
+
- Versioned, deterministic, size-limited (max 512 bytes).
|
|
32
|
+
- Fields: `ver` (version), `id` (code hash), `int` (intent owner), `iss` (issuer, optional), `p` (params, optional).
|
|
33
|
+
- When `iss` field is present, both issuer and intent owner must sign the transaction.
|
|
31
34
|
- Perfect for attaching to transactions or off-chain messages for tracing.
|
|
32
35
|
|
|
33
36
|
3. Canonical Message
|
|
@@ -45,137 +48,159 @@ The **Wallet Strategy** is the simplest approach where codes are generated direc
|
|
|
45
48
|
|
|
46
49
|
#### How it works:
|
|
47
50
|
```typescript
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
import { ActionCodesProtocol } from '@actioncodes/protocol';
|
|
52
|
+
import { SolanaAdapter } from '@actioncodes/protocol';
|
|
50
53
|
|
|
51
|
-
//
|
|
52
|
-
const
|
|
54
|
+
// Initialize protocol
|
|
55
|
+
const protocol = new ActionCodesProtocol({
|
|
56
|
+
codeLength: 8, // Code length (6-24 digits)
|
|
57
|
+
ttlMs: 120000, // Time to live (2 minutes)
|
|
58
|
+
clockSkewMs: 5000 // Clock skew tolerance (5 seconds)
|
|
59
|
+
});
|
|
53
60
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
// Optional: provide secret for enhanced security
|
|
57
|
-
// const result = await protocol.generateCode("wallet", canonicalMessage, signature, "optional-secret");
|
|
61
|
+
// Register Solana adapter
|
|
62
|
+
protocol.registerAdapter('solana', new SolanaAdapter());
|
|
58
63
|
|
|
59
|
-
//
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
signature
|
|
64
|
-
}
|
|
64
|
+
// 1. Generate code with wallet strategy
|
|
65
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
66
|
+
// Sign the canonical message with user's wallet
|
|
67
|
+
const signature = await userWallet.signMessage(message);
|
|
68
|
+
return signature; // Returns base58-encoded signature
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const actionCode = await protocol.generate(
|
|
72
|
+
"wallet",
|
|
73
|
+
userWallet.publicKey.toString(),
|
|
74
|
+
"solana",
|
|
75
|
+
signFn
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// 2. Validate code
|
|
79
|
+
protocol.validate("wallet", actionCode);
|
|
80
|
+
// Throws ProtocolError if validation fails
|
|
65
81
|
```
|
|
66
82
|
|
|
67
83
|
#### Key Features:
|
|
68
84
|
- **Signature-based security** - Codes require a valid signature over the canonical message (prevents public key + timestamp attacks)
|
|
69
85
|
- **Direct wallet binding** - Codes are cryptographically tied to the user's public key
|
|
70
|
-
- **
|
|
86
|
+
- **HMAC-based generation** - Uses signature as entropy source for secure code generation
|
|
71
87
|
- **Immediate validation** - No delegation certificates needed
|
|
72
|
-
- **Perfect for** - Direct user interactions, simple authentication flows
|
|
88
|
+
- **Perfect for** - Direct user interactions, simple authentication flows, transaction authorization
|
|
73
89
|
|
|
74
90
|
#### Security Model:
|
|
75
91
|
- **Signature verification** - All codes require a valid signature over the canonical message
|
|
76
92
|
- **Public key + timestamp attack prevention** - Signatures prevent attackers from generating codes with just public key + timestamp
|
|
77
|
-
- Codes
|
|
78
|
-
-
|
|
93
|
+
- **HMAC-based entropy** - Codes use HMAC-SHA256 with signature as key, ensuring cryptographic security
|
|
94
|
+
- Codes are bound to the specific public key and timestamp
|
|
79
95
|
- Time-based expiration prevents replay attacks
|
|
80
96
|
- Canonical message signing ensures integrity
|
|
81
97
|
|
|
82
98
|
### 2. Delegation Strategy (Advanced)
|
|
83
99
|
|
|
84
|
-
The **Delegation Strategy** allows users to pre-authorize actions through delegation
|
|
100
|
+
The **Delegation Strategy** allows users to pre-authorize actions through delegation proofs, enabling more complex workflows like relayer services.
|
|
85
101
|
|
|
86
102
|
#### How it works:
|
|
87
103
|
|
|
88
|
-
##### Step 1: Create Delegation
|
|
104
|
+
##### Step 1: Create Delegation Proof
|
|
89
105
|
```typescript
|
|
90
|
-
|
|
91
|
-
const template = await protocol.createDelegationCertificateTemplate(
|
|
92
|
-
userPublicKey,
|
|
93
|
-
3600000, // 1 hour expiration
|
|
94
|
-
"solana"
|
|
95
|
-
);
|
|
106
|
+
import { serializeDelegationProof } from '@actioncodes/protocol';
|
|
96
107
|
|
|
97
|
-
// User
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
signature:
|
|
108
|
+
// User creates a delegation proof
|
|
109
|
+
const delegationProof = {
|
|
110
|
+
walletPubkey: userWallet.publicKey.toString(),
|
|
111
|
+
delegatedPubkey: delegatedKeypair.publicKey.toString(),
|
|
112
|
+
chain: "solana",
|
|
113
|
+
expiresAt: Date.now() + 3600000, // 1 hour expiration
|
|
114
|
+
signature: "" // Will be set after signing
|
|
104
115
|
};
|
|
116
|
+
|
|
117
|
+
// User signs the delegation proof
|
|
118
|
+
const delegationMessage = serializeDelegationProof(delegationProof);
|
|
119
|
+
const delegationSignature = await userWallet.signMessage(delegationMessage);
|
|
120
|
+
delegationProof.signature = delegationSignature;
|
|
105
121
|
```
|
|
106
122
|
|
|
107
123
|
##### Step 2: Generate Delegated Codes
|
|
108
124
|
```typescript
|
|
109
|
-
//
|
|
110
|
-
const
|
|
111
|
-
const
|
|
125
|
+
// Sign function for delegated keypair
|
|
126
|
+
const delegatedSignFn = async (message: Uint8Array, chain: string) => {
|
|
127
|
+
const signature = await delegatedKeypair.signMessage(message);
|
|
128
|
+
return signature;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Generate code using delegation strategy
|
|
132
|
+
const delegatedActionCode = await protocol.generate(
|
|
133
|
+
"delegation",
|
|
134
|
+
delegationProof,
|
|
135
|
+
"solana",
|
|
136
|
+
delegatedSignFn
|
|
137
|
+
);
|
|
112
138
|
```
|
|
113
139
|
|
|
114
140
|
##### Step 3: Validate Delegated Codes
|
|
115
141
|
```typescript
|
|
116
|
-
// Validate the delegated code
|
|
117
|
-
|
|
142
|
+
// Validate the delegated code
|
|
143
|
+
protocol.validate("delegation", delegatedActionCode);
|
|
144
|
+
// Throws ProtocolError if validation fails
|
|
118
145
|
```
|
|
119
146
|
|
|
120
147
|
#### Key Features:
|
|
121
148
|
- **Pre-authorization** - Users can authorize actions for a limited time
|
|
122
149
|
- **Relayer support** - Third parties can validate codes without generating them
|
|
123
|
-
- **
|
|
124
|
-
- **Time-limited** -
|
|
150
|
+
- **Proof-based** - Codes are bound to specific delegation proofs
|
|
151
|
+
- **Time-limited** - Delegation proofs have expiration times
|
|
125
152
|
- **Perfect for** - Relayer services, automated systems, complex workflows
|
|
126
153
|
|
|
127
154
|
#### Security Model:
|
|
128
|
-
- **Code-
|
|
129
|
-
- **Signature Verification** -
|
|
130
|
-
- **
|
|
131
|
-
- **Cross-
|
|
132
|
-
- **Relayer Security** - Relayers can validate codes but cannot generate them without the
|
|
155
|
+
- **Code-Proof Binding** - Codes are cryptographically bound to their specific delegation proof
|
|
156
|
+
- **Signature Verification** - Delegation proof signatures are verified using chain adapters
|
|
157
|
+
- **Dual Signature Requirement** - Both wallet signature (on proof) and delegated signature (on code) are required
|
|
158
|
+
- **Cross-Proof Protection** - Codes from one delegation proof cannot be used with another
|
|
159
|
+
- **Relayer Security** - Relayers can validate codes but cannot generate them without the delegated keypair's signature
|
|
133
160
|
|
|
134
161
|
#### Important Security Guarantees:
|
|
135
162
|
|
|
136
|
-
1. **Stolen Delegation
|
|
137
|
-
- Delegation
|
|
138
|
-
- They cannot be used to generate
|
|
139
|
-
-
|
|
163
|
+
1. **Stolen Delegation Proofs are Limited**
|
|
164
|
+
- Delegation proofs contain public data (pubkeys, expiration, chain)
|
|
165
|
+
- They cannot be used to generate codes without the delegated keypair's private key
|
|
166
|
+
- The proof signature prevents tampering but doesn't enable code generation
|
|
140
167
|
|
|
141
168
|
2. **Stolen Signatures Cannot Create Valid Codes**
|
|
142
169
|
- Even if an attacker steals a signature, they cannot create valid codes
|
|
143
|
-
- Codes are bound to the ENTIRE
|
|
144
|
-
- Different
|
|
170
|
+
- Codes are bound to the ENTIRE delegation proof (not just the signature)
|
|
171
|
+
- Different proof data = different code = validation failure
|
|
145
172
|
|
|
146
173
|
3. **Relayer Code Generation Prevention**
|
|
147
|
-
- Relayers cannot generate codes even with public
|
|
148
|
-
-
|
|
149
|
-
- Only the
|
|
174
|
+
- Relayers cannot generate codes even with public delegation proof data
|
|
175
|
+
- Codes require signatures from the delegated keypair (private asset)
|
|
176
|
+
- Only holders of the delegated keypair can generate valid codes
|
|
150
177
|
|
|
151
|
-
4. **Code-
|
|
152
|
-
- Codes are cryptographically linked to their specific
|
|
153
|
-
- Cross-
|
|
154
|
-
- Each
|
|
178
|
+
4. **Code-Proof Binding**
|
|
179
|
+
- Codes are cryptographically linked to their specific delegation proof
|
|
180
|
+
- Cross-proof attacks are impossible
|
|
181
|
+
- Each delegation proof produces unique codes
|
|
155
182
|
|
|
156
|
-
#### Delegation
|
|
183
|
+
#### Delegation Proof Structure:
|
|
157
184
|
```typescript
|
|
158
|
-
interface
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
expiresAt: number;
|
|
163
|
-
|
|
164
|
-
chain: string; // Target blockchain
|
|
165
|
-
signature: string; // User's signature of the certificate
|
|
185
|
+
interface DelegationProof {
|
|
186
|
+
walletPubkey: string; // Original wallet's public key
|
|
187
|
+
delegatedPubkey: string; // Delegated keypair's public key
|
|
188
|
+
chain: string; // Target blockchain
|
|
189
|
+
expiresAt: number; // Expiration timestamp
|
|
190
|
+
signature: string; // Wallet's signature of the delegation proof
|
|
166
191
|
}
|
|
167
192
|
```
|
|
168
193
|
|
|
169
194
|
#### Delegated Action Code Structure:
|
|
170
195
|
```typescript
|
|
171
196
|
interface DelegatedActionCode {
|
|
172
|
-
code: string;
|
|
173
|
-
pubkey: string;
|
|
174
|
-
timestamp: number;
|
|
175
|
-
expiresAt: number;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
197
|
+
code: string; // The actual action code
|
|
198
|
+
pubkey: string; // Delegated pubkey (who signs the code)
|
|
199
|
+
timestamp: number; // Generation timestamp
|
|
200
|
+
expiresAt: number; // Code expiration
|
|
201
|
+
signature: string; // Signature from delegated keypair
|
|
202
|
+
chain: string; // Target blockchain
|
|
203
|
+
delegationProof: DelegationProof; // The delegation proof
|
|
179
204
|
}
|
|
180
205
|
```
|
|
181
206
|
|
|
@@ -186,72 +211,106 @@ interface DelegatedActionCode {
|
|
|
186
211
|
#### 1. Simple Authentication
|
|
187
212
|
```typescript
|
|
188
213
|
// User logs into a dApp
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
214
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
215
|
+
return await userWallet.signMessage(message);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const actionCode = await protocol.generate(
|
|
219
|
+
"wallet",
|
|
220
|
+
userWallet.publicKey.toString(),
|
|
221
|
+
"solana",
|
|
222
|
+
signFn
|
|
223
|
+
);
|
|
192
224
|
|
|
193
225
|
// dApp validates the code
|
|
194
|
-
|
|
195
|
-
chain: "solana",
|
|
196
|
-
pubkey: userWallet.publicKey,
|
|
197
|
-
signature: signature
|
|
198
|
-
});
|
|
226
|
+
protocol.validate("wallet", actionCode);
|
|
199
227
|
```
|
|
200
228
|
|
|
201
229
|
#### 2. Transaction Authorization
|
|
202
230
|
```typescript
|
|
231
|
+
import { buildProtocolMeta, codeHash } from '@actioncodes/protocol';
|
|
232
|
+
|
|
203
233
|
// User authorizes a specific transaction
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
234
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
235
|
+
return await userWallet.signMessage(message);
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
const actionCode = await protocol.generate(
|
|
239
|
+
"wallet",
|
|
240
|
+
userWallet.publicKey.toString(),
|
|
241
|
+
"solana",
|
|
242
|
+
signFn
|
|
243
|
+
);
|
|
209
244
|
|
|
210
245
|
// Relayer validates before executing
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
246
|
+
protocol.validate("wallet", actionCode);
|
|
247
|
+
|
|
248
|
+
// Attach protocol meta to transaction
|
|
249
|
+
const adapter = protocol.getAdapter("solana") as SolanaAdapter;
|
|
250
|
+
const meta = buildProtocolMeta({
|
|
251
|
+
ver: 2,
|
|
252
|
+
id: codeHash(actionCode.code),
|
|
253
|
+
int: actionCode.pubkey,
|
|
215
254
|
});
|
|
255
|
+
const txWithMeta = SolanaAdapter.attachProtocolMeta(transactionBase64, meta);
|
|
256
|
+
|
|
257
|
+
// Verify transaction is signed by the intended owner
|
|
258
|
+
adapter.verifyTransactionSignedByIntentOwner(txWithMeta);
|
|
216
259
|
```
|
|
217
260
|
|
|
218
261
|
### Delegation Strategy Use Cases
|
|
219
262
|
|
|
220
263
|
#### 1. Relayer Services
|
|
221
264
|
```typescript
|
|
222
|
-
// User
|
|
223
|
-
const
|
|
265
|
+
// User creates delegation proof for relayer
|
|
266
|
+
const delegationProof = {
|
|
267
|
+
walletPubkey: userWallet.publicKey.toString(),
|
|
268
|
+
delegatedPubkey: relayerKeypair.publicKey.toString(),
|
|
269
|
+
chain: "solana",
|
|
270
|
+
expiresAt: Date.now() + 3600000, // 1 hour
|
|
271
|
+
signature: await signDelegationProof(delegationProof)
|
|
272
|
+
};
|
|
224
273
|
|
|
225
274
|
// Relayer can validate codes but not generate them
|
|
226
|
-
const relayer = new RelayerService();
|
|
227
|
-
relayer.registerCertificate(certificate);
|
|
228
|
-
|
|
229
275
|
// User generates codes that relayer can validate
|
|
230
|
-
const
|
|
231
|
-
|
|
276
|
+
const delegatedSignFn = async (message: Uint8Array, chain: string) => {
|
|
277
|
+
return await relayerKeypair.signMessage(message);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const actionCode = await protocol.generate(
|
|
281
|
+
"delegation",
|
|
282
|
+
delegationProof,
|
|
283
|
+
"solana",
|
|
284
|
+
delegatedSignFn
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
// Relayer validates the code
|
|
288
|
+
protocol.validate("delegation", actionCode);
|
|
232
289
|
```
|
|
233
290
|
|
|
234
291
|
#### 2. Automated Trading Bots
|
|
235
292
|
```typescript
|
|
236
|
-
// User authorizes trading bot for
|
|
237
|
-
const
|
|
293
|
+
// User authorizes trading bot for 24 hours
|
|
294
|
+
const delegationProof = {
|
|
295
|
+
walletPubkey: userWallet.publicKey.toString(),
|
|
296
|
+
delegatedPubkey: botKeypair.publicKey.toString(),
|
|
297
|
+
chain: "solana",
|
|
298
|
+
expiresAt: Date.now() + 86400000, // 24 hours
|
|
299
|
+
signature: await signDelegationProof(delegationProof)
|
|
300
|
+
};
|
|
238
301
|
|
|
239
|
-
// Bot
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
302
|
+
// Bot generates codes using delegated keypair
|
|
303
|
+
const botSignFn = async (message: Uint8Array, chain: string) => {
|
|
304
|
+
return await botKeypair.signMessage(message);
|
|
305
|
+
};
|
|
243
306
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
]);
|
|
252
|
-
|
|
253
|
-
// Any authorized user can generate codes
|
|
254
|
-
const actionCode = await protocol.generateCode("delegation", sharedCertificate);
|
|
307
|
+
const tradeCode = await protocol.generate(
|
|
308
|
+
"delegation",
|
|
309
|
+
delegationProof,
|
|
310
|
+
"solana",
|
|
311
|
+
botSignFn
|
|
312
|
+
);
|
|
313
|
+
// Bot executes trade with this code
|
|
255
314
|
```
|
|
256
315
|
|
|
257
316
|
## Security Considerations
|
|
@@ -271,32 +330,37 @@ const actionCode = await protocol.generateCode("delegation", sharedCertificate);
|
|
|
271
330
|
- Cannot be reused
|
|
272
331
|
|
|
273
332
|
4. **Delegation Security**
|
|
274
|
-
- Delegation
|
|
275
|
-
- Codes are bound to specific
|
|
276
|
-
- Cross-
|
|
333
|
+
- Delegation proofs are cryptographically signed
|
|
334
|
+
- Codes are bound to specific delegation proofs
|
|
335
|
+
- Cross-proof attacks are impossible
|
|
277
336
|
|
|
278
337
|
### Best Practices
|
|
279
338
|
|
|
280
|
-
1. **
|
|
281
|
-
-
|
|
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
|
|
339
|
+
1. **Delegation Proof Expiration**
|
|
340
|
+
- Set appropriate expiration times for delegation proofs
|
|
287
341
|
- Shorter expiration = higher security
|
|
288
342
|
- Longer expiration = better UX
|
|
289
343
|
|
|
290
|
-
|
|
291
|
-
- Only trust relayers with
|
|
344
|
+
2. **Relayer Security**
|
|
345
|
+
- Only trust relayers with valid delegation proofs
|
|
292
346
|
- Never share private keys with relayers
|
|
293
347
|
- Monitor relayer behavior
|
|
294
348
|
|
|
349
|
+
3. **Issuer Field Usage**
|
|
350
|
+
- Use `iss` field when issuer and intent owner are different entities
|
|
351
|
+
- Ensure both signatures are present when `iss` is specified
|
|
352
|
+
- Omit `iss` when it's the same as `int` to save space
|
|
353
|
+
|
|
295
354
|
4. **Code Validation**
|
|
296
355
|
- Always validate codes server-side
|
|
297
356
|
- Check expiration times
|
|
298
357
|
- Verify the binding to the correct public key
|
|
299
358
|
|
|
359
|
+
5. **Protocol Meta with Issuer**
|
|
360
|
+
- Use `iss` field when issuer differs from intent owner
|
|
361
|
+
- When `iss` is present, ensure transaction is signed by both
|
|
362
|
+
- If `iss` equals `int`, it's automatically omitted (optimization)
|
|
363
|
+
|
|
300
364
|
## Performance
|
|
301
365
|
|
|
302
366
|
- **Code Generation**: ~1ms per code
|
|
@@ -312,29 +376,58 @@ npm install @actioncodes/protocol
|
|
|
312
376
|
|
|
313
377
|
# Basic usage
|
|
314
378
|
import { ActionCodesProtocol } from '@actioncodes/protocol';
|
|
379
|
+
import { SolanaAdapter } from '@actioncodes/protocol';
|
|
315
380
|
|
|
316
|
-
|
|
381
|
+
// Initialize protocol
|
|
382
|
+
const protocol = new ActionCodesProtocol({
|
|
383
|
+
codeLength: 8, // Code length (6-24 digits)
|
|
384
|
+
ttlMs: 120000, // Time to live (2 minutes)
|
|
385
|
+
clockSkewMs: 5000 // Clock skew tolerance (5 seconds)
|
|
386
|
+
});
|
|
317
387
|
|
|
318
|
-
//
|
|
319
|
-
|
|
388
|
+
// Register Solana adapter
|
|
389
|
+
protocol.registerAdapter('solana', new SolanaAdapter());
|
|
320
390
|
|
|
321
|
-
//
|
|
322
|
-
const
|
|
391
|
+
// 1. Sign function for wallet
|
|
392
|
+
const signFn = async (message: Uint8Array, chain: string) => {
|
|
393
|
+
// Sign the canonical message with your wallet
|
|
394
|
+
const signature = await yourWallet.signMessage(message);
|
|
395
|
+
return signature; // Returns base58-encoded signature
|
|
396
|
+
};
|
|
323
397
|
|
|
324
|
-
//
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
398
|
+
// 2. Generate a code
|
|
399
|
+
const actionCode = await protocol.generate(
|
|
400
|
+
"wallet",
|
|
401
|
+
yourWallet.publicKey.toString(),
|
|
402
|
+
"solana",
|
|
403
|
+
signFn
|
|
404
|
+
);
|
|
328
405
|
|
|
329
|
-
//
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
406
|
+
// 3. Validate a code
|
|
407
|
+
protocol.validate("wallet", actionCode);
|
|
408
|
+
// Throws ProtocolError if validation fails
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Protocol Meta with Issuer Field
|
|
412
|
+
|
|
413
|
+
When you need to separate the issuer (who created the code) from the intent owner (who will use it):
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { buildProtocolMeta } from '@actioncodes/protocol';
|
|
417
|
+
|
|
418
|
+
// Create protocol meta with issuer
|
|
419
|
+
const meta = buildProtocolMeta({
|
|
420
|
+
ver: 2,
|
|
421
|
+
id: codeHash(actionCode.code),
|
|
422
|
+
int: intentOwnerPubkey, // Who will use the code
|
|
423
|
+
iss: issuerPubkey, // Who issued the code (optional)
|
|
334
424
|
});
|
|
425
|
+
|
|
426
|
+
// If iss is same as int, it's automatically omitted to save space
|
|
427
|
+
// If iss is present, transaction must be signed by BOTH int and iss
|
|
335
428
|
```
|
|
336
429
|
|
|
337
430
|
#### Vision
|
|
338
431
|
|
|
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.
|
|
432
|
+
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.
|
|
340
433
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolanaAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SolanaAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EAEvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAQhE,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEnE,eAAO,MAAM,kBAAkB,EAAG,QAAiB,CAAC;AAEpD,qBAAa,aAAc,SAAQ,gBAAgB;IACjD,0CAA0C;IAC1C,OAAO,CAAC,eAAe;IAOvB,mEAAmE;IACnE,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO;IA6BjD,wCAAwC;IACxC,oBAAoB,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO;IAkFvE,0EAA0E;IAC1E,sBAAsB,CACpB,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO;IA8BV,0BAA0B,CACxB,mBAAmB,EAAE,mBAAmB,EACxC,eAAe,EAAE,MAAM,GACtB,OAAO;IAiFV,gFAAgF;IAChF,MAAM,CAAC,oBAAoB,CACzB,IAAI,EAAE,kBAAkB,GACvB,sBAAsB;IAKzB,yFAAyF;IACzF,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAoBhD,2EAA2E;IAC3E,OAAO,CAAC,sBAAsB;IA2B9B,iGAAiG;IACjG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAMtD,uEAAuE;IACvE,OAAO,CAAC,mBAAmB;IAmC3B;;;OAGG;IACH,4BAA4B,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAiC5E;;;;OAIG;IACH,oCAAoC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"SolanaAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/SolanaAdapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,WAAW,EACX,oBAAoB,EACpB,sBAAsB,EAEvB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAQhE,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEnE,eAAO,MAAM,kBAAkB,EAAG,QAAiB,CAAC;AAEpD,qBAAa,aAAc,SAAQ,gBAAgB;IACjD,0CAA0C;IAC1C,OAAO,CAAC,eAAe;IAOvB,mEAAmE;IACnE,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO;IA6BjD,wCAAwC;IACxC,oBAAoB,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,OAAO;IAkFvE,0EAA0E;IAC1E,sBAAsB,CACpB,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO;IA8BV,0BAA0B,CACxB,mBAAmB,EAAE,mBAAmB,EACxC,eAAe,EAAE,MAAM,GACtB,OAAO;IAiFV,gFAAgF;IAChF,MAAM,CAAC,oBAAoB,CACzB,IAAI,EAAE,kBAAkB,GACvB,sBAAsB;IAKzB,yFAAyF;IACzF,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAoBhD,2EAA2E;IAC3E,OAAO,CAAC,sBAAsB;IA2B9B,iGAAiG;IACjG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAMtD,uEAAuE;IACvE,OAAO,CAAC,mBAAmB;IAmC3B;;;OAGG;IACH,4BAA4B,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAiC5E;;;;OAIG;IACH,oCAAoC,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAgH5D,gCAAgC,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,IAAI;IA2BP;;;OAGG;IACH,MAAM,CAAC,kBAAkB,CACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,kBAAkB,GACvB,MAAM;CAoFV"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const PROTOCOL_NORMALIZATION = "NFC";
|
|
2
|
-
export declare const PROTOCOL_META_MAX_BYTES =
|
|
2
|
+
export declare const PROTOCOL_META_MAX_BYTES = 512;
|
|
3
3
|
export declare const CODE_MIN_LENGTH = 6;
|
|
4
4
|
export declare const CODE_MAX_LENGTH = 24;
|
|
5
5
|
export declare const CODE_DEFAULT_LENGTH = 8;
|
package/dist/errors.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare enum ProtocolErrorCode {
|
|
|
8
8
|
META_MISMATCH = "META_MISMATCH",
|
|
9
9
|
META_TOO_LARGE = "META_TOO_LARGE",
|
|
10
10
|
TRANSACTION_NOT_SIGNED_BY_INTENDED_OWNER = "TRANSACTION_NOT_SIGNED_BY_INTENDED_OWNER",
|
|
11
|
+
TRANSACTION_NOT_SIGNED_BY_ISSUER = "TRANSACTION_NOT_SIGNED_BY_ISSUER",
|
|
11
12
|
INVALID_TRANSACTION_FORMAT = "INVALID_TRANSACTION_FORMAT",
|
|
12
13
|
INVALID_PUBKEY_FORMAT = "INVALID_PUBKEY_FORMAT",
|
|
13
14
|
INVALID_INPUT = "INVALID_INPUT",
|
|
@@ -29,6 +30,7 @@ export declare class ProtocolError extends Error {
|
|
|
29
30
|
static metaMismatch(expected: string, actual: string, field: string): MetaMismatchError;
|
|
30
31
|
static metaTooLarge(maxBytes: number, actualBytes: number): ProtocolError;
|
|
31
32
|
static transactionNotSignedByIntendedOwner(intended: string, actualSigners: string[]): TransactionNotSignedByIntendedOwnerError;
|
|
33
|
+
static transactionNotSignedByIssuer(issuer: string, actualSigners: string[]): TransactionNotSignedByIssuerError;
|
|
32
34
|
static invalidTransactionFormat(reason: string): ProtocolError;
|
|
33
35
|
static invalidPubkeyFormat(pubkey: string, reason: string): InvalidPubkeyFormatError;
|
|
34
36
|
static invalidInput(field: string, value: unknown, reason: string): ProtocolError;
|
|
@@ -50,6 +52,9 @@ export declare class MetaMismatchError extends ProtocolError {
|
|
|
50
52
|
export declare class TransactionNotSignedByIntendedOwnerError extends ProtocolError {
|
|
51
53
|
constructor(intended: string, actualSigners: string[]);
|
|
52
54
|
}
|
|
55
|
+
export declare class TransactionNotSignedByIssuerError extends ProtocolError {
|
|
56
|
+
constructor(issuer: string, actualSigners: string[]);
|
|
57
|
+
}
|
|
53
58
|
export declare class InvalidPubkeyFormatError extends ProtocolError {
|
|
54
59
|
constructor(pubkey: string, reason: string);
|
|
55
60
|
}
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,oBAAY,iBAAiB;IAE3B,YAAY,iBAAiB;IAC7B,YAAY,iBAAiB;IAC7B,mBAAmB,wBAAwB;IAC3C,iBAAiB,sBAAsB;IAGvC,YAAY,iBAAiB;IAC7B,mBAAmB,wBAAwB;IAC3C,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IAGjC,wCAAwC,6CAA6C;IACrF,gCAAgC,qCAAqC;IACrE,0BAA0B,+BAA+B;IACzD,qBAAqB,0BAA0B;IAG/C,aAAa,kBAAkB;IAC/B,sBAAsB,2BAA2B;IAGjD,YAAY,iBAAiB;IAC7B,cAAc,mBAAmB;IAGjC,eAAe,oBAAoB;CACpC;AAED,qBAAa,aAAc,SAAQ,KAAK;aAEpB,IAAI,EAAE,iBAAiB;aAEvB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAFjC,IAAI,EAAE,iBAAiB,EACvC,OAAO,EAAE,MAAM,EACC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,YAAA;IAOnD,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB;IAI1F,MAAM,CAAC,WAAW,IAAI,aAAa;IAQnC,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,sBAAsB;IAI9E,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB;IAK9D,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAItC,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAQvD,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,iBAAiB;IAIvF,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,aAAa;IASzE,MAAM,CAAC,mCAAmC,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,wCAAwC;IAI/H,MAAM,CAAC,4BAA4B,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,iCAAiC;IAI/G,MAAM,CAAC,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IAQ9D,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,wBAAwB;IAKpF,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa;IAQjF,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa;IASzD,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa;IAQpE,MAAM,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa;IASnD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB;IAK3D,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;CAG1G;AAGD,qBAAa,gBAAiB,SAAQ,aAAa;gBACrC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;CAQjE;AAED,qBAAa,gBAAiB,SAAQ,aAAa;;CAQlD;AAED,qBAAa,iBAAkB,SAAQ,aAAa;gBACtC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAQ5D;AAED,qBAAa,wCAAyC,SAAQ,aAAa;gBAC7D,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE;CAUtD;AAED,qBAAa,iCAAkC,SAAQ,aAAa;gBACtD,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE;CAUpD;AAED,qBAAa,wBAAyB,SAAQ,aAAa;gBAC7C,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQ3C;AAED,qBAAa,qBAAsB,SAAQ,aAAa;gBAC1C,MAAM,EAAE,MAAM;CAM3B;AAED,qBAAa,sBAAuB,SAAQ,aAAa;gBAC3C,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAQzC;AAED,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,OAAO,EAAE,MAAM;CAI5B"}
|