@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.
- package/LICENSE +1 -1
- package/README.md +318 -33
- package/dist/ActionCodesProtocol.d.ts +37 -0
- package/dist/ActionCodesProtocol.d.ts.map +1 -0
- package/dist/adapters/BaseChainAdapter.d.ts +22 -0
- package/dist/adapters/BaseChainAdapter.d.ts.map +1 -0
- package/dist/adapters/SolanaAdapter.d.ts +44 -0
- package/dist/adapters/SolanaAdapter.d.ts.map +1 -0
- package/dist/constants.d.ts +6 -8
- package/dist/constants.d.ts.map +1 -1
- package/dist/errors.d.ts +63 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +25 -0
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -36
- package/dist/index.js.map +25 -0
- package/dist/strategy/DelegationStrategy.d.ts +45 -0
- package/dist/strategy/DelegationStrategy.d.ts.map +1 -0
- package/dist/strategy/WalletStrategy.d.ts +8 -0
- package/dist/strategy/WalletStrategy.d.ts.map +1 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/canonical.d.ts +5 -0
- package/dist/utils/canonical.d.ts.map +1 -0
- package/dist/utils/crypto.d.ts +13 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/protocolMeta.d.ts +16 -0
- package/dist/utils/protocolMeta.d.ts.map +1 -0
- package/docs/ActionCodesProtocol/README.md +11 -0
- package/docs/ActionCodesProtocol/classes/ActionCodesProtocol.md +147 -0
- package/docs/README.md +10 -50
- package/docs/adapters/BaseChainAdapter/README.md +20 -0
- package/docs/adapters/BaseChainAdapter/classes/BaseChainAdapter.md +56 -0
- package/docs/adapters/BaseChainAdapter/interfaces/BaseContext.md +17 -0
- package/docs/adapters/BaseChainAdapter/interfaces/ChainAdapter.md +33 -0
- package/docs/adapters/BaseChainAdapter/type-aliases/ChainContext.md +23 -0
- package/docs/adapters/NodeCryptoAdapter/README.md +15 -0
- package/docs/adapters/NodeCryptoAdapter/classes/NodeCryptoAdapter.md +254 -0
- package/docs/adapters/NodeCryptoAdapter/type-aliases/NodeCryptoContext.md +27 -0
- package/docs/adapters/SolanaAdapter/README.md +16 -0
- package/docs/adapters/SolanaAdapter/classes/SolanaAdapter.md +190 -0
- package/docs/adapters/SolanaAdapter/type-aliases/SolanaContext.md +27 -0
- package/docs/adapters/SolanaAdapter/type-aliases/SolanaTransaction.md +13 -0
- package/docs/constants/README.md +8 -13
- package/docs/constants/variables/CODE_CHARSET_DIGITS.md +11 -0
- package/docs/constants/variables/CODE_DEFAULT_LENGTH.md +11 -0
- package/docs/constants/variables/CODE_MAX_LENGTH.md +11 -0
- package/docs/constants/variables/CODE_MIN_LENGTH.md +11 -0
- package/docs/constants/variables/PROTOCOL_META_MAX_BYTES.md +11 -0
- package/docs/constants/variables/PROTOCOL_NORMALIZATION.md +11 -0
- package/docs/constants/variables/SUPPORTED_CHAINS.md +3 -3
- package/docs/errors/README.md +22 -0
- package/docs/errors/classes/ExpiredCodeError.md +695 -0
- package/docs/errors/classes/InvalidCodeFormatError.md +691 -0
- package/docs/errors/classes/InvalidPubkeyFormatError.md +691 -0
- package/docs/errors/classes/InvalidSignatureError.md +687 -0
- package/docs/errors/classes/MetaMismatchError.md +695 -0
- package/docs/errors/classes/MissingMetaError.md +681 -0
- package/docs/errors/classes/ProtocolError.md +637 -0
- package/docs/errors/classes/TransactionNotSignedByIntendedOwnerError.md +691 -0
- package/docs/errors/enumerations/ProtocolErrorCode.md +121 -0
- package/docs/index/README.md +83 -41
- package/docs/modules.md +12 -9
- package/docs/strategy/WalletStrategy/README.md +11 -0
- package/docs/strategy/WalletStrategy/classes/WalletStrategy.md +67 -0
- package/docs/types/README.md +14 -0
- package/docs/types/interfaces/ActionCode.md +65 -0
- package/docs/types/interfaces/CanonicalMessageParts.md +33 -0
- package/docs/types/interfaces/CodeGenerationConfig.md +33 -0
- package/docs/types/interfaces/CodeGenerationResult.md +25 -0
- package/docs/utils/canonical/README.md +16 -0
- package/docs/utils/canonical/functions/serializeCanonical.md +21 -0
- package/docs/utils/canonical/variables/CANONICAL_MESSAGE_PREFIX.md +11 -0
- package/docs/utils/canonical/variables/CANONICAL_MESSAGE_VERSION.md +11 -0
- package/docs/utils/crypto/README.md +18 -0
- package/docs/utils/crypto/functions/base32EncodeCrockford.md +21 -0
- package/docs/utils/crypto/functions/codeHash.md +21 -0
- package/docs/utils/crypto/functions/digestToDigits.md +25 -0
- package/docs/utils/crypto/functions/generateRandomSecret.md +15 -0
- package/docs/utils/crypto/functions/hkdfSha256.md +35 -0
- package/docs/utils/crypto/functions/hmacSha256.md +25 -0
- package/docs/utils/crypto/functions/sha256.md +21 -0
- package/docs/utils/crypto/functions/truncateBits.md +25 -0
- package/docs/utils/protocolMeta/README.md +21 -0
- package/docs/utils/protocolMeta/functions/buildProtocolMeta.md +21 -0
- package/docs/utils/protocolMeta/functions/parseProtocolMeta.md +21 -0
- package/docs/utils/protocolMeta/functions/validateProtocolMetaFormat.md +21 -0
- package/docs/utils/protocolMeta/interfaces/ProtocolMetaFields.md +41 -0
- package/docs/utils/protocolMeta/variables/SCHEME.md +11 -0
- package/package.json +42 -47
- package/dist/actioncode.d.ts +0 -120
- package/dist/actioncode.d.ts.map +0 -1
- package/dist/actioncode.js +0 -186
- package/dist/adapters/base.d.ts +0 -93
- package/dist/adapters/base.d.ts.map +0 -1
- package/dist/adapters/base.js +0 -65
- package/dist/adapters/solana/index.d.ts +0 -2
- package/dist/adapters/solana/index.d.ts.map +0 -1
- package/dist/adapters/solana/index.js +0 -30
- package/dist/adapters/solana/solana.d.ts +0 -113
- package/dist/adapters/solana/solana.d.ts.map +0 -1
- package/dist/adapters/solana/solana.js +0 -537
- package/dist/codegen.d.ts +0 -76
- package/dist/codegen.d.ts.map +0 -1
- package/dist/codegen.js +0 -211
- package/dist/constants.js +0 -24
- package/dist/meta.d.ts +0 -54
- package/dist/meta.d.ts.map +0 -1
- package/dist/meta.js +0 -104
- package/dist/protocol.d.ts +0 -179
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -390
- package/docs/_media/LICENSE +0 -201
- package/docs/_media/README.md +0 -28
- package/docs/actioncode/README.md +0 -21
- package/docs/actioncode/classes/ActionCode.md +0 -430
- package/docs/actioncode/interfaces/ActionCodeFields.md +0 -89
- package/docs/actioncode/interfaces/ActionCodeMetadata.md +0 -25
- package/docs/actioncode/interfaces/ActionCodeTransaction.md +0 -57
- package/docs/actioncode/type-aliases/ActionCodeStatus.md +0 -11
- package/docs/adapters/base/README.md +0 -11
- package/docs/adapters/base/classes/BaseChainAdapter.md +0 -396
- package/docs/adapters/solana/README.md +0 -19
- package/docs/adapters/solana/solana/README.md +0 -15
- package/docs/adapters/solana/solana/classes/SolanaAdapter.md +0 -506
- package/docs/adapters/solana/solana/type-aliases/SolanaTransaction.md +0 -13
- package/docs/codegen/README.md +0 -11
- package/docs/codegen/classes/CodeGenerator.md +0 -341
- package/docs/constants/type-aliases/SupportedChain.md +0 -11
- package/docs/constants/variables/CODE_LENGTH.md +0 -11
- package/docs/constants/variables/CODE_TTL.md +0 -11
- package/docs/constants/variables/MAX_PREFIX_LENGTH.md +0 -11
- package/docs/constants/variables/MIN_PREFIX_LENGTH.md +0 -11
- package/docs/constants/variables/PROTOCOL_CODE_PREFIX.md +0 -11
- package/docs/constants/variables/PROTOCOL_PREFIX.md +0 -11
- package/docs/constants/variables/PROTOCOL_VERSION.md +0 -11
- package/docs/meta/README.md +0 -15
- package/docs/meta/classes/ProtocolMetaParser.md +0 -177
- package/docs/meta/interfaces/ProtocolMetaV1.md +0 -59
- package/docs/protocol/README.md +0 -51
- package/docs/protocol/classes/ActionCodesProtocol.md +0 -676
- package/docs/protocol/interfaces/ProtocolConfig.md +0 -71
@@ -1,537 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
// Copyright 2025 Trana, Inc.
|
3
|
-
//
|
4
|
-
// Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
-
// you may not use this file except in compliance with the License.
|
6
|
-
// You may obtain a copy of the License at
|
7
|
-
//
|
8
|
-
// http://www.apache.org/licenses/LICENSE-2.0
|
9
|
-
//
|
10
|
-
// Unless required by applicable law or agreed to in writing, software
|
11
|
-
// distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
-
// See the License for the specific language governing permissions and
|
14
|
-
// limitations under the License.
|
15
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
16
|
-
if (k2 === undefined) k2 = k;
|
17
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
18
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
19
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
20
|
-
}
|
21
|
-
Object.defineProperty(o, k2, desc);
|
22
|
-
}) : (function(o, m, k, k2) {
|
23
|
-
if (k2 === undefined) k2 = k;
|
24
|
-
o[k2] = m[k];
|
25
|
-
}));
|
26
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
27
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
28
|
-
}) : function(o, v) {
|
29
|
-
o["default"] = v;
|
30
|
-
});
|
31
|
-
var __importStar = (this && this.__importStar) || (function () {
|
32
|
-
var ownKeys = function(o) {
|
33
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
34
|
-
var ar = [];
|
35
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
36
|
-
return ar;
|
37
|
-
};
|
38
|
-
return ownKeys(o);
|
39
|
-
};
|
40
|
-
return function (mod) {
|
41
|
-
if (mod && mod.__esModule) return mod;
|
42
|
-
var result = {};
|
43
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
44
|
-
__setModuleDefault(result, mod);
|
45
|
-
return result;
|
46
|
-
};
|
47
|
-
})();
|
48
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
49
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
50
|
-
};
|
51
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
52
|
-
exports.SolanaAdapter = void 0;
|
53
|
-
const web3_js_1 = require("@solana/web3.js");
|
54
|
-
const spl_memo_1 = require("@solana/spl-memo");
|
55
|
-
const meta_1 = require("../../meta");
|
56
|
-
const base_1 = require("../base");
|
57
|
-
const nacl = __importStar(require("tweetnacl"));
|
58
|
-
const actioncode_1 = require("../../actioncode");
|
59
|
-
const buffer_1 = require("buffer");
|
60
|
-
const bs58_1 = __importDefault(require("bs58"));
|
61
|
-
/**
|
62
|
-
* Simple Solana adapter for protocol meta operations
|
63
|
-
* Supports both legacy and versioned transactions
|
64
|
-
*/
|
65
|
-
class SolanaAdapter extends base_1.BaseChainAdapter {
|
66
|
-
constructor() {
|
67
|
-
super(...arguments);
|
68
|
-
this.chain = 'solana';
|
69
|
-
}
|
70
|
-
/**
|
71
|
-
* Encode protocol meta as a Solana memo instruction
|
72
|
-
* @param meta - The protocol meta to encode
|
73
|
-
* @returns TransactionInstruction for the memo
|
74
|
-
*/
|
75
|
-
encodeMeta(meta) {
|
76
|
-
const metaString = meta_1.ProtocolMetaParser.serialize(meta);
|
77
|
-
const signerPubkeys = [];
|
78
|
-
try {
|
79
|
-
if (meta.iss && meta.iss !== 'undefined') {
|
80
|
-
const pubkey = new web3_js_1.PublicKey(meta.iss);
|
81
|
-
signerPubkeys.push(pubkey);
|
82
|
-
}
|
83
|
-
}
|
84
|
-
catch (error) {
|
85
|
-
// Ignore error, issuer is not a valid public key
|
86
|
-
}
|
87
|
-
return (0, spl_memo_1.createMemoInstruction)(metaString, signerPubkeys);
|
88
|
-
}
|
89
|
-
/**
|
90
|
-
* Decode protocol meta from Solana transaction (legacy or versioned)
|
91
|
-
* @param tx - The Solana transaction (can be deserialized object or base64 string)
|
92
|
-
* @returns Decoded ProtocolMetaV1 or null if not found
|
93
|
-
*/
|
94
|
-
decodeMeta(tx) {
|
95
|
-
// If it's a string, deserialize it first
|
96
|
-
if (typeof tx === 'string') {
|
97
|
-
try {
|
98
|
-
tx = this.deserializeTransaction(tx);
|
99
|
-
}
|
100
|
-
catch {
|
101
|
-
return null;
|
102
|
-
}
|
103
|
-
}
|
104
|
-
// Check if it's a versioned transaction
|
105
|
-
if ('message' in tx && tx.message) {
|
106
|
-
return this.decodeVersionedTransaction(tx);
|
107
|
-
}
|
108
|
-
else if ('instructions' in tx && Array.isArray(tx.instructions)) {
|
109
|
-
return this.decodeLegacyTransaction(tx);
|
110
|
-
}
|
111
|
-
else {
|
112
|
-
return null;
|
113
|
-
}
|
114
|
-
}
|
115
|
-
/**
|
116
|
-
* Deserialize a Solana transaction from base64 string
|
117
|
-
* @param base64String - Base64 encoded transaction
|
118
|
-
* @returns SolanaTransaction object
|
119
|
-
*/
|
120
|
-
deserializeTransaction(base64String) {
|
121
|
-
try {
|
122
|
-
const buffer = buffer_1.Buffer.from(base64String, 'base64');
|
123
|
-
// Try legacy first, then versioned
|
124
|
-
try {
|
125
|
-
return web3_js_1.Transaction.from(buffer);
|
126
|
-
}
|
127
|
-
catch {
|
128
|
-
return web3_js_1.VersionedTransaction.deserialize(buffer);
|
129
|
-
}
|
130
|
-
}
|
131
|
-
catch (error) {
|
132
|
-
throw new Error('Failed to deserialize Solana transaction');
|
133
|
-
}
|
134
|
-
}
|
135
|
-
/**
|
136
|
-
* Inject protocol meta into Solana transaction
|
137
|
-
* @param serializedTx - Serialized transaction string (base64)
|
138
|
-
* @param meta - ProtocolMetaV1 object
|
139
|
-
* @returns Serialized transaction with injected meta
|
140
|
-
*/
|
141
|
-
injectMeta(serializedTx, meta) {
|
142
|
-
// Deserialize the transaction using existing pattern
|
143
|
-
const tx = this.deserializeTransaction(serializedTx);
|
144
|
-
const metaIx = this.encodeMeta(meta);
|
145
|
-
if (tx instanceof web3_js_1.VersionedTransaction) {
|
146
|
-
// Convert TransactionInstruction to MessageCompiledInstruction for versioned transactions
|
147
|
-
// Create new static account keys array with all required keys
|
148
|
-
const newStaticAccountKeys = [...tx.message.staticAccountKeys];
|
149
|
-
// Add any missing keys from the memo instruction
|
150
|
-
metaIx.keys.forEach(({ pubkey }) => {
|
151
|
-
if (!newStaticAccountKeys.some(key => key.equals(pubkey))) {
|
152
|
-
newStaticAccountKeys.push(pubkey);
|
153
|
-
}
|
154
|
-
});
|
155
|
-
// Ensure programId is also in static keys
|
156
|
-
if (!newStaticAccountKeys.some(key => key.equals(metaIx.programId))) {
|
157
|
-
newStaticAccountKeys.push(metaIx.programId);
|
158
|
-
}
|
159
|
-
// Create new compiled instructions array
|
160
|
-
const newCompiledInstructions = [...tx.message.compiledInstructions];
|
161
|
-
// Find the program ID index in the new static keys
|
162
|
-
const programIdIndex = newStaticAccountKeys.findIndex(key => key.equals(metaIx.programId));
|
163
|
-
const accountKeyIndexes = metaIx.keys.map(key => {
|
164
|
-
const index = newStaticAccountKeys.findIndex(staticKey => staticKey.equals(key.pubkey));
|
165
|
-
if (index === -1) {
|
166
|
-
throw new Error(`Account key ${key.pubkey.toBase58()} not found in static account keys`);
|
167
|
-
}
|
168
|
-
return index;
|
169
|
-
});
|
170
|
-
const compiledInstruction = {
|
171
|
-
programIdIndex,
|
172
|
-
accountKeyIndexes,
|
173
|
-
data: metaIx.data
|
174
|
-
};
|
175
|
-
newCompiledInstructions.push(compiledInstruction);
|
176
|
-
// Create new MessageV0 with updated data
|
177
|
-
const newMessage = new web3_js_1.MessageV0({
|
178
|
-
header: tx.message.header,
|
179
|
-
staticAccountKeys: newStaticAccountKeys,
|
180
|
-
recentBlockhash: tx.message.recentBlockhash,
|
181
|
-
compiledInstructions: newCompiledInstructions,
|
182
|
-
addressTableLookups: tx.message.addressTableLookups,
|
183
|
-
});
|
184
|
-
// Create new VersionedTransaction
|
185
|
-
const newVersionedTx = new web3_js_1.VersionedTransaction(newMessage);
|
186
|
-
return buffer_1.Buffer.from(newVersionedTx.serialize()).toString('base64');
|
187
|
-
}
|
188
|
-
else if (tx instanceof web3_js_1.Transaction) {
|
189
|
-
tx.instructions.push(metaIx);
|
190
|
-
// Clear existing signatures since we modified the transaction
|
191
|
-
tx.signatures = [];
|
192
|
-
// Serialize the transaction back without requiring signatures
|
193
|
-
return tx.serialize({ requireAllSignatures: false }).toString('base64');
|
194
|
-
}
|
195
|
-
else {
|
196
|
-
throw new Error('Invalid transaction type');
|
197
|
-
}
|
198
|
-
}
|
199
|
-
/**
|
200
|
-
* Validate transaction with protocol meta and authority list
|
201
|
-
* @param tx - The Solana transaction
|
202
|
-
* @param authorities - Array of valid protocol authority public keys (base58)
|
203
|
-
* @param expectedPrefix - Expected protocol prefix (default: 'DEFAULT')
|
204
|
-
* @returns True if transaction is valid
|
205
|
-
*/
|
206
|
-
validate(tx, authorities, expectedPrefix = 'DEFAULT') {
|
207
|
-
return this.detectTampering(tx, authorities, expectedPrefix);
|
208
|
-
}
|
209
|
-
/**
|
210
|
-
* Check if the issuer has signed the transaction
|
211
|
-
* @param tx - The Solana transaction (can be deserialized object or base64 string)
|
212
|
-
* @param issuer - Issuer public key to check
|
213
|
-
* @returns True if issuer has signed
|
214
|
-
*/
|
215
|
-
hasIssuerSignature(tx, issuer) {
|
216
|
-
// If it's a string, deserialize it first
|
217
|
-
if (typeof tx === 'string') {
|
218
|
-
try {
|
219
|
-
tx = this.deserializeTransaction(tx);
|
220
|
-
}
|
221
|
-
catch {
|
222
|
-
return false;
|
223
|
-
}
|
224
|
-
}
|
225
|
-
// Check if it's a versioned transaction
|
226
|
-
if ('message' in tx && tx.message) {
|
227
|
-
return this.hasIssuerSignatureVersioned(tx, issuer);
|
228
|
-
}
|
229
|
-
else if ('signatures' in tx && Array.isArray(tx.signatures)) {
|
230
|
-
return this.hasIssuerSignatureLegacy(tx, issuer);
|
231
|
-
}
|
232
|
-
else {
|
233
|
-
return false;
|
234
|
-
}
|
235
|
-
}
|
236
|
-
/**
|
237
|
-
* Decode protocol meta from legacy Solana transaction
|
238
|
-
*/
|
239
|
-
decodeLegacyTransaction(transaction) {
|
240
|
-
for (const instruction of transaction.instructions) {
|
241
|
-
if (instruction.programId.equals(SolanaAdapter.MEMO_PROGRAM_ID)) {
|
242
|
-
const memoData = instruction.data;
|
243
|
-
if (memoData && memoData.length > 0) {
|
244
|
-
try {
|
245
|
-
const memoString = new TextDecoder().decode(memoData);
|
246
|
-
const meta = meta_1.ProtocolMetaParser.parse(memoString);
|
247
|
-
if (meta && meta.version === '1') {
|
248
|
-
return meta;
|
249
|
-
}
|
250
|
-
// Continue searching if this memo is not a valid protocol meta
|
251
|
-
}
|
252
|
-
catch {
|
253
|
-
// Continue searching if this memo cannot be parsed
|
254
|
-
}
|
255
|
-
}
|
256
|
-
}
|
257
|
-
}
|
258
|
-
return null;
|
259
|
-
}
|
260
|
-
/**
|
261
|
-
* Decode protocol meta from versioned Solana transaction
|
262
|
-
*/
|
263
|
-
decodeVersionedTransaction(transaction) {
|
264
|
-
const message = transaction.message;
|
265
|
-
if (message instanceof web3_js_1.MessageV0) {
|
266
|
-
return this.decodeMessageV0(message);
|
267
|
-
}
|
268
|
-
else {
|
269
|
-
return null;
|
270
|
-
}
|
271
|
-
}
|
272
|
-
/**
|
273
|
-
* Decode protocol meta from MessageV0
|
274
|
-
*/
|
275
|
-
decodeMessageV0(message) {
|
276
|
-
for (const instruction of message.compiledInstructions) {
|
277
|
-
const programId = message.staticAccountKeys[instruction.programIdIndex];
|
278
|
-
if (programId.equals(SolanaAdapter.MEMO_PROGRAM_ID)) {
|
279
|
-
const memoData = instruction.data;
|
280
|
-
if (memoData && memoData.length > 0) {
|
281
|
-
try {
|
282
|
-
const memoString = new TextDecoder().decode(memoData);
|
283
|
-
const meta = meta_1.ProtocolMetaParser.parse(memoString);
|
284
|
-
if (meta && meta.version === '1') {
|
285
|
-
return meta;
|
286
|
-
}
|
287
|
-
// Continue searching if this memo is not a valid protocol meta
|
288
|
-
}
|
289
|
-
catch {
|
290
|
-
// Continue searching if this memo cannot be parsed
|
291
|
-
}
|
292
|
-
}
|
293
|
-
}
|
294
|
-
}
|
295
|
-
return null;
|
296
|
-
}
|
297
|
-
/**
|
298
|
-
* Check if the issuer has signed a legacy transaction
|
299
|
-
*/
|
300
|
-
hasIssuerSignatureLegacy(transaction, issuer) {
|
301
|
-
return transaction.signatures.some(sig => sig.publicKey.toBase58() === issuer);
|
302
|
-
}
|
303
|
-
/**
|
304
|
-
* Check if the issuer has signed a versioned transaction
|
305
|
-
*/
|
306
|
-
hasIssuerSignatureVersioned(transaction, issuer) {
|
307
|
-
const message = transaction.message;
|
308
|
-
if (message instanceof web3_js_1.MessageV0) {
|
309
|
-
// Check static account keys
|
310
|
-
for (const key of message.staticAccountKeys) {
|
311
|
-
if (key.toBase58() === issuer) {
|
312
|
-
return true;
|
313
|
-
}
|
314
|
-
}
|
315
|
-
}
|
316
|
-
return false;
|
317
|
-
}
|
318
|
-
/**
|
319
|
-
* Validate Solana transaction integrity with additional checks
|
320
|
-
* @param tx - The Solana transaction
|
321
|
-
* @param meta - Decoded protocol meta
|
322
|
-
* @returns True if transaction integrity is valid
|
323
|
-
*/
|
324
|
-
validateTransactionIntegrity(tx, meta) {
|
325
|
-
// Additional Solana-specific validation can be added here
|
326
|
-
// For example, checking transaction signatures, recent blockhash, etc.
|
327
|
-
// Verify that the memo instruction contains the expected protocol meta
|
328
|
-
const decodedMeta = this.decodeMeta(tx);
|
329
|
-
if (!decodedMeta) {
|
330
|
-
return false;
|
331
|
-
}
|
332
|
-
if (!meta.iss) {
|
333
|
-
return false;
|
334
|
-
}
|
335
|
-
if (!this.hasIssuerSignature(tx, meta.iss)) {
|
336
|
-
return false;
|
337
|
-
}
|
338
|
-
// Cross-check the decoded meta with the provided meta
|
339
|
-
return (decodedMeta.version === meta.version &&
|
340
|
-
decodedMeta.prefix === meta.prefix &&
|
341
|
-
decodedMeta.initiator === meta.initiator &&
|
342
|
-
decodedMeta.id === meta.id &&
|
343
|
-
decodedMeta.iss === meta.iss &&
|
344
|
-
decodedMeta.params === meta.params);
|
345
|
-
}
|
346
|
-
verifyCodeSignature(actionCode) {
|
347
|
-
try {
|
348
|
-
const message = this.getCodeSignatureMessage(actionCode.code, actionCode.timestamp, actionCode.prefix);
|
349
|
-
const messageBytes = new TextEncoder().encode(message);
|
350
|
-
const pubkeyBytes = new web3_js_1.PublicKey(actionCode.pubkey).toBytes();
|
351
|
-
const sigBytes = bs58_1.default.decode(actionCode.signature);
|
352
|
-
return nacl.sign.detached.verify(messageBytes, sigBytes, pubkeyBytes);
|
353
|
-
}
|
354
|
-
catch (error) {
|
355
|
-
return false;
|
356
|
-
}
|
357
|
-
}
|
358
|
-
/**
|
359
|
-
* Decode protocol meta from base64 string (for backward compatibility)
|
360
|
-
* @param base64String - Base64 encoded transaction
|
361
|
-
* @returns Decoded ProtocolMetaV1 or null
|
362
|
-
*/
|
363
|
-
decodeFromBase64(base64String) {
|
364
|
-
return this.decodeMeta(base64String);
|
365
|
-
}
|
366
|
-
/**
|
367
|
-
* Sign the transaction with the protocol key
|
368
|
-
* @param actionCode - The action code containing the transaction
|
369
|
-
* @param key - The keypair to sign with
|
370
|
-
* @returns Promise that resolves to the signed action code
|
371
|
-
*/
|
372
|
-
async signWithProtocolKey(actionCode, key) {
|
373
|
-
try {
|
374
|
-
if (!actionCode.transaction?.transaction) {
|
375
|
-
throw new Error('No transaction found');
|
376
|
-
}
|
377
|
-
const tx = this.deserializeTransaction(actionCode.transaction.transaction);
|
378
|
-
// Check if transaction has protocol meta
|
379
|
-
const meta = this.decodeMeta(tx);
|
380
|
-
if (!meta) {
|
381
|
-
throw new Error('Invalid transaction, protocol meta not found');
|
382
|
-
}
|
383
|
-
// Validate transaction integrity
|
384
|
-
if (!this.validateTransactionIntegrity(tx, meta)) {
|
385
|
-
throw new Error('Invalid transaction, transaction integrity not valid');
|
386
|
-
}
|
387
|
-
// Sign the transaction
|
388
|
-
if (tx instanceof web3_js_1.Transaction) {
|
389
|
-
tx.partialSign(key);
|
390
|
-
}
|
391
|
-
else if (tx instanceof web3_js_1.VersionedTransaction) {
|
392
|
-
tx.sign([key]);
|
393
|
-
}
|
394
|
-
else {
|
395
|
-
throw new Error('Invalid transaction type');
|
396
|
-
}
|
397
|
-
const updatedTransaction = {
|
398
|
-
...actionCode.transaction,
|
399
|
-
transaction: tx.serialize({ requireAllSignatures: false }).toString('base64'),
|
400
|
-
};
|
401
|
-
const updatedFields = {
|
402
|
-
...actionCode.json,
|
403
|
-
transaction: updatedTransaction,
|
404
|
-
};
|
405
|
-
return actioncode_1.ActionCode.fromPayload(updatedFields);
|
406
|
-
}
|
407
|
-
catch (error) {
|
408
|
-
throw new Error(`Failed to sign transaction with protocol key: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
409
|
-
}
|
410
|
-
}
|
411
|
-
/**
|
412
|
-
* Verify the finalized transaction from blockchain
|
413
|
-
* @param tx - The finalized transaction response from blockchain
|
414
|
-
* @param actionCode - The action code to verify against
|
415
|
-
* @returns True if the transaction is valid and matches the action code
|
416
|
-
*/
|
417
|
-
verifyFinalizedTransaction(tx, actionCode) {
|
418
|
-
try {
|
419
|
-
// Handle null/undefined transaction
|
420
|
-
if (tx.transaction === null || tx.transaction === undefined) {
|
421
|
-
return false;
|
422
|
-
}
|
423
|
-
// Both legacy and versioned responses have message and signatures
|
424
|
-
const response = tx.transaction;
|
425
|
-
if (!response.message || !response.signatures) {
|
426
|
-
return false;
|
427
|
-
}
|
428
|
-
let transaction;
|
429
|
-
// Check if it's a versioned transaction by looking at the message structure
|
430
|
-
if (response.message instanceof web3_js_1.MessageV0) {
|
431
|
-
// Versioned transaction - reconstruct from message and signatures
|
432
|
-
transaction = new web3_js_1.VersionedTransaction(response.message);
|
433
|
-
// Note: In a real scenario, signatures would be attached, but for testing we just need the message
|
434
|
-
}
|
435
|
-
else {
|
436
|
-
// Legacy transaction - reconstruct from compiled message and signatures
|
437
|
-
const compiledMessage = response.message;
|
438
|
-
transaction = web3_js_1.Transaction.populate(compiledMessage, response.signatures);
|
439
|
-
}
|
440
|
-
const meta = this.decodeMeta(transaction);
|
441
|
-
if (!meta) {
|
442
|
-
return false; // No protocol meta found
|
443
|
-
}
|
444
|
-
if (!meta.iss) {
|
445
|
-
return false; // No issuer field in meta
|
446
|
-
}
|
447
|
-
if (!actionCode.codeHash) {
|
448
|
-
return false; // No codeHash available
|
449
|
-
}
|
450
|
-
if (!meta.id || meta.id !== actionCode.codeHash) {
|
451
|
-
return false; // ID doesn't match expected value
|
452
|
-
}
|
453
|
-
if (meta.prefix !== actionCode.prefix) {
|
454
|
-
return false;
|
455
|
-
}
|
456
|
-
if (meta.initiator !== actionCode.pubkey) {
|
457
|
-
return false;
|
458
|
-
}
|
459
|
-
let userPubkey = null;
|
460
|
-
try {
|
461
|
-
userPubkey = new web3_js_1.PublicKey(actionCode.pubkey);
|
462
|
-
}
|
463
|
-
catch (error) {
|
464
|
-
return false;
|
465
|
-
}
|
466
|
-
if (userPubkey) {
|
467
|
-
if (transaction instanceof web3_js_1.VersionedTransaction) {
|
468
|
-
const message = transaction.message;
|
469
|
-
if (message instanceof web3_js_1.MessageV0) {
|
470
|
-
// Check if user's public key is in the static account keys
|
471
|
-
const userKeyIndex = message.staticAccountKeys.findIndex(key => key.equals(userPubkey));
|
472
|
-
if (userKeyIndex === -1) {
|
473
|
-
return false; // User's key not found in transaction
|
474
|
-
}
|
475
|
-
// Check if user's key is a signer (first bit of header indicates signer status)
|
476
|
-
const isUserSigner = (message.header.numRequiredSignatures > 0) &&
|
477
|
-
(userKeyIndex < message.header.numRequiredSignatures);
|
478
|
-
if (!isUserSigner) {
|
479
|
-
return false; // User didn't sign the transaction
|
480
|
-
}
|
481
|
-
}
|
482
|
-
else {
|
483
|
-
return false; // Unsupported message type
|
484
|
-
}
|
485
|
-
}
|
486
|
-
else if (transaction instanceof web3_js_1.Transaction) {
|
487
|
-
// For legacy transactions, check if user's key is in the account keys
|
488
|
-
const accountKeys = transaction.compileMessage().accountKeys;
|
489
|
-
const userKeyIndex = accountKeys.findIndex(key => key.equals(userPubkey));
|
490
|
-
if (userKeyIndex === -1) {
|
491
|
-
return false; // User's key not found in transaction
|
492
|
-
}
|
493
|
-
// Check if user's key is a signer
|
494
|
-
const isUserSigner = userKeyIndex < transaction.compileMessage().header.numRequiredSignatures;
|
495
|
-
if (!isUserSigner) {
|
496
|
-
return false; // User didn't sign the transaction
|
497
|
-
}
|
498
|
-
}
|
499
|
-
else {
|
500
|
-
return false; // Invalid transaction type
|
501
|
-
}
|
502
|
-
}
|
503
|
-
// 5. Check that tx is signed by protocol (issuer)
|
504
|
-
if (!this.hasIssuerSignature(transaction, meta.iss)) {
|
505
|
-
return false; // Protocol didn't sign the transaction
|
506
|
-
}
|
507
|
-
// All checks passed
|
508
|
-
return true;
|
509
|
-
}
|
510
|
-
catch (error) {
|
511
|
-
// If any error occurs during verification, return false
|
512
|
-
return false;
|
513
|
-
}
|
514
|
-
}
|
515
|
-
/**
|
516
|
-
* Validate a signed message for sign-only mode
|
517
|
-
* @param message - The message that was signed
|
518
|
-
* @param signedMessage - The signed message (base64 or hex)
|
519
|
-
* @param pubkey - The public key that should have signed the message
|
520
|
-
* @returns True if the signature is valid
|
521
|
-
*/
|
522
|
-
validateSignedMessage(message, signedMessage, pubkey) {
|
523
|
-
try {
|
524
|
-
// Decode the public key (base58)
|
525
|
-
const publicKeyBytes = bs58_1.default.decode(pubkey);
|
526
|
-
// Decode the signature as base58 (Solana convention)
|
527
|
-
const signature = bs58_1.default.decode(signedMessage);
|
528
|
-
const messageBuffer = buffer_1.Buffer.from(message, 'utf8');
|
529
|
-
return nacl.sign.detached.verify(messageBuffer, signature, publicKeyBytes);
|
530
|
-
}
|
531
|
-
catch (e) {
|
532
|
-
return false;
|
533
|
-
}
|
534
|
-
}
|
535
|
-
}
|
536
|
-
exports.SolanaAdapter = SolanaAdapter;
|
537
|
-
SolanaAdapter.MEMO_PROGRAM_ID = spl_memo_1.MEMO_PROGRAM_ID;
|
package/dist/codegen.d.ts
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
export declare class CodeGenerator {
|
2
|
-
static TIME_WINDOW_MS: number;
|
3
|
-
static CODE_DIGITS: number;
|
4
|
-
static MIN_PREFIX_LENGTH: number;
|
5
|
-
static MAX_PREFIX_LENGTH: number;
|
6
|
-
/**
|
7
|
-
* Validate prefix format
|
8
|
-
* @param prefix - The prefix to validate
|
9
|
-
* @returns True if prefix is valid, false otherwise
|
10
|
-
*/
|
11
|
-
static validatePrefix(prefix: string): boolean;
|
12
|
-
/**
|
13
|
-
* Validate generated code format (prefix + exactly 8 digits)
|
14
|
-
* @param code - The code to validate
|
15
|
-
* @returns True if code is valid, false otherwise
|
16
|
-
*/
|
17
|
-
static validateCodeFormat(code: string): boolean;
|
18
|
-
/**
|
19
|
-
* Validate that the numeric part of a code is exactly 8 digits
|
20
|
-
* @param code - The code to validate (can include prefix)
|
21
|
-
* @returns True if numeric part is valid, false otherwise
|
22
|
-
*/
|
23
|
-
static validateCodeDigits(code: string): boolean;
|
24
|
-
/**
|
25
|
-
* Normalize prefix - convert PROTOCOL_CODE_PREFIX to empty string, validate others
|
26
|
-
* @param prefix - The prefix to normalize
|
27
|
-
* @returns Normalized prefix
|
28
|
-
* @throws Error if prefix is invalid
|
29
|
-
*/
|
30
|
-
static normalizePrefix(prefix: string): string;
|
31
|
-
/**
|
32
|
-
* Generate a deterministic 8-digit code based on public key, prefix, and timestamp
|
33
|
-
* @param pubkey - Solana wallet public key (base58)
|
34
|
-
* @param prefix - Optional namespace prefix (default: PROTOCOL_CODE_PREFIX)
|
35
|
-
* @param timestamp - UNIX timestamp in milliseconds (defaults to now)
|
36
|
-
* @returns Object containing code, issuedAt, and expiresAt timestamps
|
37
|
-
* @throws Error if generated code is invalid
|
38
|
-
*/
|
39
|
-
static generateCode(pubkey: string, prefix?: string, timestamp?: number): {
|
40
|
-
code: string;
|
41
|
-
issuedAt: number;
|
42
|
-
expiresAt: number;
|
43
|
-
};
|
44
|
-
/**
|
45
|
-
* Derive the full SHA-256 hash for storage or encryption key generation
|
46
|
-
* @param pubkey - Solana wallet public key (base58)
|
47
|
-
* @param prefix - Optional namespace prefix (default: PROTOCOL_CODE_PREFIX)
|
48
|
-
* @param timestamp - UNIX timestamp in milliseconds (defaults to now)
|
49
|
-
* @returns Full SHA-256 hash string
|
50
|
-
*/
|
51
|
-
static deriveCodeHash(pubkey: string, prefix?: string, timestamp?: number): string;
|
52
|
-
/**
|
53
|
-
* Get the expected code for a given public key and timestamp
|
54
|
-
* @param pubkey - Solana wallet public key (base58)
|
55
|
-
* @param timestamp - UNIX timestamp in milliseconds
|
56
|
-
* @param prefix - Optional namespace prefix (default: PROTOCOL_CODE_PREFIX)
|
57
|
-
* @returns Full code string with prefix + 8 digits
|
58
|
-
*/
|
59
|
-
static getExpectedCode(pubkey: string, timestamp: number, prefix?: string): string;
|
60
|
-
/**
|
61
|
-
* Validate if a code matches the expected code for a given public key and timestamp
|
62
|
-
* @param code - The code to validate (can include prefix)
|
63
|
-
* @param pubkey - Solana wallet public key (base58)
|
64
|
-
* @param timestamp - UNIX timestamp in milliseconds
|
65
|
-
* @param prefix - Optional namespace prefix (default: PROTOCOL_CODE_PREFIX)
|
66
|
-
* @returns True if code matches expected code and timestamp is valid
|
67
|
-
*/
|
68
|
-
static validateCode(code: string, pubkey: string, timestamp: number, prefix?: string): boolean;
|
69
|
-
/**
|
70
|
-
* Check if a timestamp falls within a valid time window
|
71
|
-
* @param timestamp - UNIX timestamp in milliseconds
|
72
|
-
* @returns True if timestamp is valid
|
73
|
-
*/
|
74
|
-
static isValidTimestamp(timestamp: number): boolean;
|
75
|
-
}
|
76
|
-
//# sourceMappingURL=codegen.d.ts.map
|
package/dist/codegen.d.ts.map
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAiBA,qBAAa,aAAa;IACtB,MAAM,CAAC,cAAc,SAAY;IACjC,MAAM,CAAC,WAAW,SAAe;IACjC,MAAM,CAAC,iBAAiB,SAAqB;IAC7C,MAAM,CAAC,iBAAiB,SAAqB;IAE7C;;;;OAIG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAM9C;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAoChD;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAkChD;;;;;OAKG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAQ9C;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CACf,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAA6B,EACrC,SAAS,GAAE,MAAmB,GAC/B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAiCxD;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,MAA6B,EACrC,SAAS,CAAC,EAAE,MAAM,GACnB,MAAM;IAQT;;;;;;OAMG;IACH,MAAM,CAAC,eAAe,CAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAA6B,GACtC,MAAM;IAIT;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAA6B,GACtC,OAAO;IAgBV;;;;OAIG;IACH,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;CAGtD"}
|