@totemsdk/core 1.0.9 → 1.0.10
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 +21 -0
- package/README.md +5 -5
- package/dist/Streamable.js +54 -31
- package/dist/adapters/index.js +18 -8
- package/dist/adapters/types.js +19 -8
- package/dist/binio.js +5 -1
- package/dist/bip39.js +24 -14
- package/dist/derive.js +11 -7
- package/dist/index.js +130 -22
- package/dist/javaStreamables.js +49 -30
- package/dist/lease/LeaseMonitor.js +7 -3
- package/dist/lease/LeaseStore.js +7 -3
- package/dist/lease/WatermarkStore.js +7 -3
- package/dist/lease/index.js +13 -4
- package/dist/lease-client.js +8 -3
- package/dist/minima32.js +22 -13
- package/dist/minimaWireSerializer.js +20 -14
- package/dist/mmr.js +35 -23
- package/dist/mx.js +10 -1
- package/dist/params.js +9 -5
- package/dist/script.js +12 -7
- package/dist/scripts/contract-helpers.js +37 -26
- package/dist/scripts/dapp-types.js +11 -6
- package/dist/scripts/index.js +38 -4
- package/dist/scripts/types.js +26 -12
- package/dist/scripts/witness-serializer.js +48 -30
- package/dist/transaction.js +55 -46
- package/dist/treekey.js +74 -58
- package/dist/tx/TransactionLifecycle.js +11 -5
- package/dist/tx/TransactionReceiptStore.js +7 -3
- package/dist/tx/TransactionService.js +14 -10
- package/dist/tx/index.js +11 -3
- package/dist/tx/types.js +2 -1
- package/dist/util.js +5 -1
- package/dist/utils.js +12 -5
- package/dist/verify.js +36 -25
- package/dist/version.js +5 -2
- package/dist/wots.js +94 -64
- package/package.json +31 -6
- package/src/Streamable.d.ts +0 -268
- package/src/Streamable.js +0 -416
- package/src/Streamable.ts +0 -567
- package/src/__tests__/Streamable.parity.test.ts +0 -422
- package/src/__tests__/perAddressDerivation.parity.test.ts +0 -152
- package/src/__tests__/roottree-prepare.test.ts +0 -101
- package/src/__tests__/wots-parity.test.ts +0 -289
- package/src/adapters/index.d.ts +0 -190
- package/src/adapters/index.js +0 -117
- package/src/adapters/index.ts +0 -301
- package/src/adapters/types.ts +0 -235
- package/src/addr.oracle.test.ts +0 -25
- package/src/address.test.ts +0 -55
- package/src/binio.ts +0 -21
- package/src/bip39.d.ts +0 -91
- package/src/bip39.js +0 -427
- package/src/bip39.ts +0 -432
- package/src/derive.d.ts +0 -2
- package/src/derive.js +0 -13
- package/src/derive.ts +0 -11
- package/src/index.d.ts +0 -26
- package/src/index.js +0 -128
- package/src/index.test.ts +0 -5
- package/src/index.ts +0 -221
- package/src/javaStreamables.d.ts +0 -233
- package/src/javaStreamables.js +0 -332
- package/src/javaStreamables.ts +0 -403
- package/src/lease/LeaseMonitor.d.ts +0 -44
- package/src/lease/LeaseMonitor.js +0 -111
- package/src/lease/LeaseMonitor.ts +0 -157
- package/src/lease/LeaseStore.d.ts +0 -57
- package/src/lease/LeaseStore.js +0 -148
- package/src/lease/LeaseStore.ts +0 -203
- package/src/lease/WatermarkStore.d.ts +0 -61
- package/src/lease/WatermarkStore.js +0 -206
- package/src/lease/WatermarkStore.ts +0 -270
- package/src/lease/index.d.ts +0 -14
- package/src/lease/index.js +0 -22
- package/src/lease/index.ts +0 -41
- package/src/lease-client.d.ts +0 -31
- package/src/lease-client.js +0 -44
- package/src/lease-client.ts +0 -69
- package/src/minima32.d.ts +0 -10
- package/src/minima32.js +0 -113
- package/src/minima32.test.ts +0 -11
- package/src/minima32.ts +0 -127
- package/src/minimaWireSerializer.d.ts +0 -189
- package/src/minimaWireSerializer.js +0 -311
- package/src/minimaWireSerializer.test.ts +0 -466
- package/src/minimaWireSerializer.ts +0 -117
- package/src/mmr.d.ts +0 -157
- package/src/mmr.js +0 -340
- package/src/mmr.oracle.test.ts +0 -28
- package/src/mmr.ts +0 -429
- package/src/mx.test.ts +0 -25
- package/src/mx.ts +0 -1
- package/src/params.d.ts +0 -29
- package/src/params.d.ts.map +0 -1
- package/src/params.js +0 -20
- package/src/params.js.map +0 -1
- package/src/params.ts +0 -44
- package/src/script.d.ts +0 -7
- package/src/script.js +0 -27
- package/src/script.ts +0 -24
- package/src/scripts/contract-helpers.ts +0 -609
- package/src/scripts/dapp-types.ts +0 -240
- package/src/scripts/index.ts +0 -22
- package/src/scripts/types.d.ts +0 -81
- package/src/scripts/types.js +0 -145
- package/src/scripts/types.ts +0 -247
- package/src/scripts/witness-serializer.ts +0 -384
- package/src/transaction.ts +0 -430
- package/src/treekey.d.ts +0 -383
- package/src/treekey.js +0 -774
- package/src/treekey.parity.test.ts +0 -459
- package/src/treekey.ts +0 -975
- package/src/tx/TransactionLifecycle.d.ts +0 -55
- package/src/tx/TransactionLifecycle.js +0 -188
- package/src/tx/TransactionLifecycle.ts +0 -280
- package/src/tx/TransactionReceiptStore.d.ts +0 -36
- package/src/tx/TransactionReceiptStore.js +0 -89
- package/src/tx/TransactionReceiptStore.ts +0 -112
- package/src/tx/TransactionService.d.ts +0 -31
- package/src/tx/TransactionService.js +0 -140
- package/src/tx/TransactionService.ts +0 -252
- package/src/tx/index.d.ts +0 -13
- package/src/tx/index.js +0 -20
- package/src/tx/index.ts +0 -44
- package/src/tx/types.d.ts +0 -80
- package/src/tx/types.js +0 -6
- package/src/tx/types.ts +0 -130
- package/src/util.d.ts +0 -1
- package/src/util.js +0 -5
- package/src/util.ts +0 -1
- package/src/utils.d.ts +0 -8
- package/src/utils.js +0 -42
- package/src/utils.ts +0 -38
- package/src/verify.ts +0 -210
- package/src/version.ts +0 -13
- package/src/wots.d.ts +0 -224
- package/src/wots.d.ts.map +0 -1
- package/src/wots.js +0 -565
- package/src/wots.js.map +0 -1
- package/src/wots.ts +0 -651
- package/test-vectors.json +0 -45
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module TransactionLifecycle
|
|
3
|
-
* Orchestrates the complete transaction flow with lease and watermark management
|
|
4
|
-
*
|
|
5
|
-
* Integrates:
|
|
6
|
-
* - TransactionService for RPC calls
|
|
7
|
-
* - LeaseStore for lease persistence
|
|
8
|
-
* - WatermarkStore for index tracking
|
|
9
|
-
* - TransactionReceiptStore for history
|
|
10
|
-
*/
|
|
11
|
-
import type { LoggerAdapter, MetricsAdapter } from '../adapters';
|
|
12
|
-
import type { LeaseStore, WatermarkStore } from '../lease';
|
|
13
|
-
import type { TransactionService } from './TransactionService';
|
|
14
|
-
import type { TransactionReceiptStore } from './TransactionReceiptStore';
|
|
15
|
-
import type { PrepareRequest, PrepareResponse, FinalizeResponse, TransactionMetadata, SignResult } from './types';
|
|
16
|
-
import type { WotsSigningDependencies } from './TransactionService';
|
|
17
|
-
export declare class TransactionLifecycleError extends Error {
|
|
18
|
-
code: number;
|
|
19
|
-
userMessage: string;
|
|
20
|
-
constructor(message: string, code: number, userMessage: string);
|
|
21
|
-
}
|
|
22
|
-
export declare class WatermarkExhaustedError extends Error {
|
|
23
|
-
constructor();
|
|
24
|
-
}
|
|
25
|
-
export interface TransactionLifecycleConfig {
|
|
26
|
-
validateWatermarkBeforePrepare?: boolean;
|
|
27
|
-
syncWatermarkBeforePrepare?: boolean;
|
|
28
|
-
}
|
|
29
|
-
export interface WatermarkSyncFunction {
|
|
30
|
-
(rootPublicKey: string): Promise<{
|
|
31
|
-
updated: boolean;
|
|
32
|
-
multiDeviceConflict: boolean;
|
|
33
|
-
}>;
|
|
34
|
-
}
|
|
35
|
-
export interface PrepareResult extends PrepareResponse {
|
|
36
|
-
metadata: TransactionMetadata;
|
|
37
|
-
}
|
|
38
|
-
export declare class TransactionLifecycle {
|
|
39
|
-
private readonly txService;
|
|
40
|
-
private readonly leaseStore;
|
|
41
|
-
private readonly watermarkStore;
|
|
42
|
-
private readonly receiptStore;
|
|
43
|
-
private readonly logger;
|
|
44
|
-
private readonly metrics;
|
|
45
|
-
private readonly config;
|
|
46
|
-
private syncWatermark?;
|
|
47
|
-
constructor(txService: TransactionService, leaseStore: LeaseStore, watermarkStore: WatermarkStore, receiptStore: TransactionReceiptStore, logger?: LoggerAdapter, metrics?: MetricsAdapter, config?: TransactionLifecycleConfig);
|
|
48
|
-
setSyncWatermarkFunction(fn: WatermarkSyncFunction): void;
|
|
49
|
-
prepare(params: PrepareRequest, rootPublicKey: string): Promise<PrepareResult>;
|
|
50
|
-
sign(prepareResult: PrepareResult, seed: Uint8Array, deps: WotsSigningDependencies, paramSetName?: string): Promise<SignResult>;
|
|
51
|
-
finalize(leaseToken: string, signedHex: string, metadata: TransactionMetadata): Promise<FinalizeResponse>;
|
|
52
|
-
cancelLease(leaseToken: string): Promise<void>;
|
|
53
|
-
private validateWatermark;
|
|
54
|
-
private parseAxiaError;
|
|
55
|
-
}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @module TransactionLifecycle
|
|
4
|
-
* Orchestrates the complete transaction flow with lease and watermark management
|
|
5
|
-
*
|
|
6
|
-
* Integrates:
|
|
7
|
-
* - TransactionService for RPC calls
|
|
8
|
-
* - LeaseStore for lease persistence
|
|
9
|
-
* - WatermarkStore for index tracking
|
|
10
|
-
* - TransactionReceiptStore for history
|
|
11
|
-
*/
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.TransactionLifecycle = exports.WatermarkExhaustedError = exports.TransactionLifecycleError = void 0;
|
|
14
|
-
const adapters_1 = require("../adapters");
|
|
15
|
-
class TransactionLifecycleError extends Error {
|
|
16
|
-
constructor(message, code, userMessage) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.code = code;
|
|
19
|
-
this.userMessage = userMessage;
|
|
20
|
-
this.name = 'TransactionLifecycleError';
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
exports.TransactionLifecycleError = TransactionLifecycleError;
|
|
24
|
-
class WatermarkExhaustedError extends Error {
|
|
25
|
-
constructor() {
|
|
26
|
-
super('All WOTS signatures have been used. Please create a new wallet.');
|
|
27
|
-
this.name = 'WatermarkExhaustedError';
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
exports.WatermarkExhaustedError = WatermarkExhaustedError;
|
|
31
|
-
class TransactionLifecycle {
|
|
32
|
-
constructor(txService, leaseStore, watermarkStore, receiptStore, logger = new adapters_1.NoopLogger(), metrics = new adapters_1.NoopMetrics(), config = {}) {
|
|
33
|
-
this.txService = txService;
|
|
34
|
-
this.leaseStore = leaseStore;
|
|
35
|
-
this.watermarkStore = watermarkStore;
|
|
36
|
-
this.receiptStore = receiptStore;
|
|
37
|
-
this.logger = logger;
|
|
38
|
-
this.metrics = metrics;
|
|
39
|
-
this.config = {
|
|
40
|
-
validateWatermarkBeforePrepare: config.validateWatermarkBeforePrepare ?? true,
|
|
41
|
-
syncWatermarkBeforePrepare: config.syncWatermarkBeforePrepare ?? true,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
setSyncWatermarkFunction(fn) {
|
|
45
|
-
this.syncWatermark = fn;
|
|
46
|
-
}
|
|
47
|
-
async prepare(params, rootPublicKey) {
|
|
48
|
-
if (this.config.validateWatermarkBeforePrepare) {
|
|
49
|
-
await this.validateWatermark(rootPublicKey);
|
|
50
|
-
}
|
|
51
|
-
try {
|
|
52
|
-
const result = await this.txService.prepare(params, rootPublicKey);
|
|
53
|
-
await this.leaseStore.save({
|
|
54
|
-
leaseId: result.leaseId,
|
|
55
|
-
leaseToken: result.leaseToken,
|
|
56
|
-
indices: { addressIndex: result.addressIndex, l1: result.l1, l2: result.l2 },
|
|
57
|
-
expiresAt: Date.now() + (result.leaseTTL * 1000),
|
|
58
|
-
status: 'active',
|
|
59
|
-
createdAt: Date.now(),
|
|
60
|
-
txId: result.txId,
|
|
61
|
-
leaseTTL: result.leaseTTL,
|
|
62
|
-
});
|
|
63
|
-
this.logger.debug(`Lease persisted: ${result.leaseId}`);
|
|
64
|
-
return {
|
|
65
|
-
...result,
|
|
66
|
-
metadata: {
|
|
67
|
-
to: params.to,
|
|
68
|
-
amount: params.amount,
|
|
69
|
-
tokenId: params.tokenId || '0x00',
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
const parsed = this.parseAxiaError(error);
|
|
75
|
-
throw new TransactionLifecycleError(error.message, parsed.code, parsed.userMessage);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async sign(prepareResult, seed, deps, paramSetName) {
|
|
79
|
-
const request = {
|
|
80
|
-
addressIndex: prepareResult.addressIndex,
|
|
81
|
-
l1: prepareResult.l1,
|
|
82
|
-
l2: prepareResult.l2,
|
|
83
|
-
digestTx: prepareResult.digestTx,
|
|
84
|
-
};
|
|
85
|
-
return this.txService.sign(request, seed, deps, paramSetName);
|
|
86
|
-
}
|
|
87
|
-
async finalize(leaseToken, signedHex, metadata) {
|
|
88
|
-
const lease = this.leaseStore.getByToken(leaseToken);
|
|
89
|
-
if (!lease) {
|
|
90
|
-
throw new TransactionLifecycleError('Lease not found', 404, 'Transaction lease not found. Please try again.');
|
|
91
|
-
}
|
|
92
|
-
try {
|
|
93
|
-
const result = await this.txService.finalize({ leaseToken, signedHex });
|
|
94
|
-
await this.watermarkStore.markUsed(lease.indices);
|
|
95
|
-
await this.watermarkStore.advanceWatermark(lease.indices);
|
|
96
|
-
await this.receiptStore.initialize();
|
|
97
|
-
await this.receiptStore.add({
|
|
98
|
-
txpowid: result.txpowid,
|
|
99
|
-
timestamp: Date.now(),
|
|
100
|
-
to: metadata.to,
|
|
101
|
-
amount: metadata.amount,
|
|
102
|
-
tokenId: metadata.tokenId,
|
|
103
|
-
indices: lease.indices,
|
|
104
|
-
status: 'confirmed',
|
|
105
|
-
txId: lease.txId,
|
|
106
|
-
leaseId: lease.leaseId,
|
|
107
|
-
});
|
|
108
|
-
await this.leaseStore.updateStatus(lease.leaseId, 'finalized');
|
|
109
|
-
await this.leaseStore.delete(lease.leaseId);
|
|
110
|
-
this.logger.debug(`Transaction finalized: ${result.txpowid}`);
|
|
111
|
-
this.logger.debug('Watermark advanced and receipt stored');
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
const parsed = this.parseAxiaError(error);
|
|
116
|
-
throw new TransactionLifecycleError(error.message, parsed.code, parsed.userMessage);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
async cancelLease(leaseToken) {
|
|
120
|
-
const lease = this.leaseStore.getByToken(leaseToken);
|
|
121
|
-
if (lease) {
|
|
122
|
-
await this.leaseStore.updateStatus(lease.leaseId, 'cancelled');
|
|
123
|
-
await this.leaseStore.delete(lease.leaseId);
|
|
124
|
-
this.logger.debug(`Lease cancelled: ${lease.leaseId}`);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
async validateWatermark(rootPublicKey) {
|
|
128
|
-
if (!this.watermarkStore.isInitialized()) {
|
|
129
|
-
await this.watermarkStore.initialize();
|
|
130
|
-
}
|
|
131
|
-
if (this.watermarkStore.isExhausted()) {
|
|
132
|
-
throw new WatermarkExhaustedError();
|
|
133
|
-
}
|
|
134
|
-
if (this.config.syncWatermarkBeforePrepare && this.syncWatermark) {
|
|
135
|
-
try {
|
|
136
|
-
this.logger.debug('Syncing watermark before transaction prepare...');
|
|
137
|
-
const syncResult = await this.syncWatermark(rootPublicKey);
|
|
138
|
-
if (syncResult.updated) {
|
|
139
|
-
this.logger.debug('Watermark synced before prepare');
|
|
140
|
-
}
|
|
141
|
-
if (syncResult.multiDeviceConflict) {
|
|
142
|
-
this.logger.warn('Multi-device conflict detected before prepare');
|
|
143
|
-
}
|
|
144
|
-
if (this.watermarkStore.isExhausted()) {
|
|
145
|
-
throw new WatermarkExhaustedError();
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
if (error instanceof WatermarkExhaustedError) {
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
this.logger.warn('Watermark sync failed before prepare:', error);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
parseAxiaError(error) {
|
|
157
|
-
const message = error.message || error.toString();
|
|
158
|
-
if (message.includes('403') || error.code === 403) {
|
|
159
|
-
return {
|
|
160
|
-
code: 403,
|
|
161
|
-
userMessage: 'Access denied. Your project may not have permission for this operation.',
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (message.includes('409') || error.code === 409) {
|
|
165
|
-
return {
|
|
166
|
-
code: 409,
|
|
167
|
-
userMessage: 'WOTS indices exhausted. Please create a new wallet.',
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
if (message.includes('410') || error.code === 410) {
|
|
171
|
-
return {
|
|
172
|
-
code: 410,
|
|
173
|
-
userMessage: 'Transaction lease expired. Please try again.',
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
if (message.includes('502') || error.code === 502) {
|
|
177
|
-
return {
|
|
178
|
-
code: 502,
|
|
179
|
-
userMessage: 'Failed to post transaction to network. Please try again.',
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
return {
|
|
183
|
-
code: 500,
|
|
184
|
-
userMessage: 'An error occurred. Please try again.',
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
exports.TransactionLifecycle = TransactionLifecycle;
|
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module TransactionLifecycle
|
|
3
|
-
* Orchestrates the complete transaction flow with lease and watermark management
|
|
4
|
-
*
|
|
5
|
-
* Integrates:
|
|
6
|
-
* - TransactionService for RPC calls
|
|
7
|
-
* - LeaseStore for lease persistence
|
|
8
|
-
* - WatermarkStore for index tracking
|
|
9
|
-
* - TransactionReceiptStore for history
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import type { LoggerAdapter, MetricsAdapter } from '../adapters/index.js';
|
|
13
|
-
import { NoopLogger, NoopMetrics } from '../adapters/index.js';
|
|
14
|
-
import type { LeaseStore, WatermarkStore, WotsIndices } from '../lease/index.js';
|
|
15
|
-
import type { TransactionService } from './TransactionService.js';
|
|
16
|
-
import type { TransactionReceiptStore } from './TransactionReceiptStore.js';
|
|
17
|
-
import type {
|
|
18
|
-
PrepareRequest,
|
|
19
|
-
PrepareResponse,
|
|
20
|
-
FinalizeResponse,
|
|
21
|
-
TransactionMetadata,
|
|
22
|
-
SignRequest,
|
|
23
|
-
SignResult,
|
|
24
|
-
} from './types.js';
|
|
25
|
-
import type { WotsSigningDependencies } from './TransactionService.js';
|
|
26
|
-
|
|
27
|
-
export class TransactionLifecycleError extends Error {
|
|
28
|
-
constructor(
|
|
29
|
-
message: string,
|
|
30
|
-
public code: number,
|
|
31
|
-
public userMessage: string
|
|
32
|
-
) {
|
|
33
|
-
super(message);
|
|
34
|
-
this.name = 'TransactionLifecycleError';
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export class WatermarkExhaustedError extends Error {
|
|
39
|
-
constructor() {
|
|
40
|
-
super('All WOTS signatures have been used. Please create a new wallet.');
|
|
41
|
-
this.name = 'WatermarkExhaustedError';
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface TransactionLifecycleConfig {
|
|
46
|
-
validateWatermarkBeforePrepare?: boolean;
|
|
47
|
-
syncWatermarkBeforePrepare?: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface WatermarkSyncFunction {
|
|
51
|
-
(rootPublicKey: string): Promise<{ updated: boolean; multiDeviceConflict: boolean }>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface PrepareResult extends PrepareResponse {
|
|
55
|
-
metadata: TransactionMetadata;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export class TransactionLifecycle {
|
|
59
|
-
private readonly txService: TransactionService;
|
|
60
|
-
private readonly leaseStore: LeaseStore;
|
|
61
|
-
private readonly watermarkStore: WatermarkStore;
|
|
62
|
-
private readonly receiptStore: TransactionReceiptStore;
|
|
63
|
-
private readonly logger: LoggerAdapter;
|
|
64
|
-
private readonly metrics: MetricsAdapter;
|
|
65
|
-
private readonly config: Required<TransactionLifecycleConfig>;
|
|
66
|
-
private syncWatermark?: WatermarkSyncFunction;
|
|
67
|
-
|
|
68
|
-
constructor(
|
|
69
|
-
txService: TransactionService,
|
|
70
|
-
leaseStore: LeaseStore,
|
|
71
|
-
watermarkStore: WatermarkStore,
|
|
72
|
-
receiptStore: TransactionReceiptStore,
|
|
73
|
-
logger: LoggerAdapter = new NoopLogger(),
|
|
74
|
-
metrics: MetricsAdapter = new NoopMetrics(),
|
|
75
|
-
config: TransactionLifecycleConfig = {}
|
|
76
|
-
) {
|
|
77
|
-
this.txService = txService;
|
|
78
|
-
this.leaseStore = leaseStore;
|
|
79
|
-
this.watermarkStore = watermarkStore;
|
|
80
|
-
this.receiptStore = receiptStore;
|
|
81
|
-
this.logger = logger;
|
|
82
|
-
this.metrics = metrics;
|
|
83
|
-
this.config = {
|
|
84
|
-
validateWatermarkBeforePrepare: config.validateWatermarkBeforePrepare ?? true,
|
|
85
|
-
syncWatermarkBeforePrepare: config.syncWatermarkBeforePrepare ?? true,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
setSyncWatermarkFunction(fn: WatermarkSyncFunction): void {
|
|
90
|
-
this.syncWatermark = fn;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async prepare(
|
|
94
|
-
params: PrepareRequest,
|
|
95
|
-
rootPublicKey: string
|
|
96
|
-
): Promise<PrepareResult> {
|
|
97
|
-
if (this.config.validateWatermarkBeforePrepare) {
|
|
98
|
-
await this.validateWatermark(rootPublicKey);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
const result = await this.txService.prepare(params, rootPublicKey);
|
|
103
|
-
|
|
104
|
-
await this.leaseStore.save({
|
|
105
|
-
leaseId: result.leaseId,
|
|
106
|
-
leaseToken: result.leaseToken,
|
|
107
|
-
indices: { addressIndex: result.addressIndex, l1: result.l1, l2: result.l2 },
|
|
108
|
-
expiresAt: Date.now() + result.leaseTTL,
|
|
109
|
-
status: 'active',
|
|
110
|
-
createdAt: Date.now(),
|
|
111
|
-
txId: result.txId,
|
|
112
|
-
leaseTTL: result.leaseTTL,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.logger.debug(`Lease persisted: ${result.leaseId}`);
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
...result,
|
|
119
|
-
metadata: {
|
|
120
|
-
to: params.to,
|
|
121
|
-
amount: params.amount,
|
|
122
|
-
tokenId: params.tokenId || '0x00',
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
} catch (error: any) {
|
|
126
|
-
const parsed = this.parseAxiaError(error);
|
|
127
|
-
throw new TransactionLifecycleError(error.message, parsed.code, parsed.userMessage);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async sign(
|
|
132
|
-
prepareResult: PrepareResult,
|
|
133
|
-
seed: Uint8Array,
|
|
134
|
-
deps: WotsSigningDependencies,
|
|
135
|
-
paramSetName?: string
|
|
136
|
-
): Promise<SignResult> {
|
|
137
|
-
const request: SignRequest = {
|
|
138
|
-
addressIndex: prepareResult.addressIndex,
|
|
139
|
-
l1: prepareResult.l1,
|
|
140
|
-
l2: prepareResult.l2,
|
|
141
|
-
digestTx: prepareResult.digestTx,
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
return this.txService.sign(request, seed, deps, paramSetName);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
async finalize(
|
|
148
|
-
leaseToken: string,
|
|
149
|
-
signedHex: string,
|
|
150
|
-
metadata: TransactionMetadata
|
|
151
|
-
): Promise<FinalizeResponse> {
|
|
152
|
-
const lease = this.leaseStore.getByToken(leaseToken);
|
|
153
|
-
if (!lease) {
|
|
154
|
-
throw new TransactionLifecycleError(
|
|
155
|
-
'Lease not found',
|
|
156
|
-
404,
|
|
157
|
-
'Transaction lease not found. Please try again.'
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
const result = await this.txService.finalize({ leaseToken, signedHex });
|
|
163
|
-
|
|
164
|
-
await this.watermarkStore.markUsed(lease.indices);
|
|
165
|
-
await this.watermarkStore.advanceWatermark(lease.indices);
|
|
166
|
-
|
|
167
|
-
await this.receiptStore.initialize();
|
|
168
|
-
await this.receiptStore.add({
|
|
169
|
-
txpowid: result.txpowid,
|
|
170
|
-
timestamp: Date.now(),
|
|
171
|
-
to: metadata.to,
|
|
172
|
-
amount: metadata.amount,
|
|
173
|
-
tokenId: metadata.tokenId,
|
|
174
|
-
indices: lease.indices,
|
|
175
|
-
status: 'confirmed',
|
|
176
|
-
txId: lease.txId,
|
|
177
|
-
leaseId: lease.leaseId,
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
await this.leaseStore.updateStatus(lease.leaseId, 'finalized');
|
|
181
|
-
await this.leaseStore.delete(lease.leaseId);
|
|
182
|
-
|
|
183
|
-
this.logger.debug(`Transaction finalized: ${result.txpowid}`);
|
|
184
|
-
this.logger.debug('Watermark advanced and receipt stored');
|
|
185
|
-
|
|
186
|
-
return result;
|
|
187
|
-
} catch (error: any) {
|
|
188
|
-
const parsed = this.parseAxiaError(error);
|
|
189
|
-
throw new TransactionLifecycleError(error.message, parsed.code, parsed.userMessage);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async cancelLease(leaseToken: string): Promise<void> {
|
|
194
|
-
const lease = this.leaseStore.getByToken(leaseToken);
|
|
195
|
-
if (lease) {
|
|
196
|
-
await this.leaseStore.updateStatus(lease.leaseId, 'cancelled');
|
|
197
|
-
await this.leaseStore.delete(lease.leaseId);
|
|
198
|
-
this.logger.debug(`Lease cancelled: ${lease.leaseId}`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private async validateWatermark(rootPublicKey: string): Promise<void> {
|
|
203
|
-
if (!this.watermarkStore.isInitialized()) {
|
|
204
|
-
await this.watermarkStore.initialize();
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (this.watermarkStore.isExhausted()) {
|
|
208
|
-
throw new WatermarkExhaustedError();
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (this.config.syncWatermarkBeforePrepare && this.syncWatermark) {
|
|
212
|
-
try {
|
|
213
|
-
this.logger.debug('Syncing watermark before transaction prepare...');
|
|
214
|
-
const syncResult = await this.syncWatermark(rootPublicKey);
|
|
215
|
-
|
|
216
|
-
if (syncResult.updated) {
|
|
217
|
-
this.logger.debug('Watermark synced before prepare');
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (syncResult.multiDeviceConflict) {
|
|
221
|
-
this.logger.warn('Multi-device conflict detected before prepare');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (this.watermarkStore.isExhausted()) {
|
|
225
|
-
throw new WatermarkExhaustedError();
|
|
226
|
-
}
|
|
227
|
-
} catch (error) {
|
|
228
|
-
if (error instanceof WatermarkExhaustedError) {
|
|
229
|
-
throw error;
|
|
230
|
-
}
|
|
231
|
-
this.logger.warn('Watermark sync failed before prepare:', error);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
private parseAxiaError(error: any): { code: number; userMessage: string } {
|
|
237
|
-
const message = error.message || error.toString();
|
|
238
|
-
|
|
239
|
-
if (error?.code === 429) {
|
|
240
|
-
const limit = error.limit ?? 10;
|
|
241
|
-
return {
|
|
242
|
-
code: 429,
|
|
243
|
-
userMessage: `Daily signing limit reached (${limit}/day). Resets at midnight UTC.`,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (message.includes('403') || error.code === 403) {
|
|
248
|
-
return {
|
|
249
|
-
code: 403,
|
|
250
|
-
userMessage: 'Access denied. Your project may not have permission for this operation.',
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (message.includes('409') || error.code === 409) {
|
|
255
|
-
return {
|
|
256
|
-
code: 409,
|
|
257
|
-
userMessage: 'WOTS indices exhausted. Please create a new wallet.',
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (message.includes('410') || error.code === 410) {
|
|
262
|
-
return {
|
|
263
|
-
code: 410,
|
|
264
|
-
userMessage: 'Transaction lease expired. Please try again.',
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (message.includes('502') || error.code === 502) {
|
|
269
|
-
return {
|
|
270
|
-
code: 502,
|
|
271
|
-
userMessage: 'Failed to post transaction to network. Please try again.',
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
return {
|
|
276
|
-
code: 500,
|
|
277
|
-
userMessage: 'An error occurred. Please try again.',
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module TransactionReceiptStore
|
|
3
|
-
* Persistent storage for transaction receipts
|
|
4
|
-
*
|
|
5
|
-
* Uses in-memory cache backed by persistent storage.
|
|
6
|
-
* Pattern:
|
|
7
|
-
* - initialize() loads from storage into memory cache
|
|
8
|
-
* - Sync getters read from memory cache (fast, no I/O)
|
|
9
|
-
* - Mutators update memory cache AND persist to storage
|
|
10
|
-
*/
|
|
11
|
-
import type { StorageAdapter, LoggerAdapter } from '../adapters';
|
|
12
|
-
import type { TransactionReceipt } from './types';
|
|
13
|
-
export interface TransactionReceiptStoreConfig {
|
|
14
|
-
storageKey?: string;
|
|
15
|
-
maxReceipts?: number;
|
|
16
|
-
}
|
|
17
|
-
export declare class TransactionReceiptStore {
|
|
18
|
-
private receipts;
|
|
19
|
-
private _initialized;
|
|
20
|
-
private readonly storageKey;
|
|
21
|
-
private readonly maxReceipts;
|
|
22
|
-
private readonly storage;
|
|
23
|
-
private readonly logger;
|
|
24
|
-
constructor(storage: StorageAdapter, logger?: LoggerAdapter, config?: TransactionReceiptStoreConfig);
|
|
25
|
-
initialize(): Promise<void>;
|
|
26
|
-
isInitialized(): boolean;
|
|
27
|
-
private load;
|
|
28
|
-
private persist;
|
|
29
|
-
add(receipt: TransactionReceipt): Promise<void>;
|
|
30
|
-
getAll(): TransactionReceipt[];
|
|
31
|
-
getByTxpowid(txpowid: string): TransactionReceipt | undefined;
|
|
32
|
-
getRecent(count?: number): TransactionReceipt[];
|
|
33
|
-
updateStatus(txpowid: string, status: TransactionReceipt['status']): Promise<void>;
|
|
34
|
-
clear(): Promise<void>;
|
|
35
|
-
count(): number;
|
|
36
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @module TransactionReceiptStore
|
|
4
|
-
* Persistent storage for transaction receipts
|
|
5
|
-
*
|
|
6
|
-
* Uses in-memory cache backed by persistent storage.
|
|
7
|
-
* Pattern:
|
|
8
|
-
* - initialize() loads from storage into memory cache
|
|
9
|
-
* - Sync getters read from memory cache (fast, no I/O)
|
|
10
|
-
* - Mutators update memory cache AND persist to storage
|
|
11
|
-
*/
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.TransactionReceiptStore = void 0;
|
|
14
|
-
const adapters_1 = require("../adapters");
|
|
15
|
-
const DEFAULT_STORAGE_KEY = 'totem_transaction_receipts';
|
|
16
|
-
const DEFAULT_MAX_RECEIPTS = 1000;
|
|
17
|
-
class TransactionReceiptStore {
|
|
18
|
-
constructor(storage, logger = new adapters_1.NoopLogger(), config = {}) {
|
|
19
|
-
this.receipts = [];
|
|
20
|
-
this._initialized = false;
|
|
21
|
-
this.storage = storage;
|
|
22
|
-
this.logger = logger;
|
|
23
|
-
this.storageKey = config.storageKey ?? DEFAULT_STORAGE_KEY;
|
|
24
|
-
this.maxReceipts = config.maxReceipts ?? DEFAULT_MAX_RECEIPTS;
|
|
25
|
-
}
|
|
26
|
-
async initialize() {
|
|
27
|
-
if (this._initialized)
|
|
28
|
-
return;
|
|
29
|
-
await this.load();
|
|
30
|
-
this._initialized = true;
|
|
31
|
-
}
|
|
32
|
-
isInitialized() {
|
|
33
|
-
return this._initialized;
|
|
34
|
-
}
|
|
35
|
-
async load() {
|
|
36
|
-
try {
|
|
37
|
-
const receipts = await this.storage.get(this.storageKey);
|
|
38
|
-
if (receipts) {
|
|
39
|
-
this.receipts = receipts;
|
|
40
|
-
this.logger.debug(`Loaded ${this.receipts.length} transaction receipts`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
this.logger.error('Failed to load receipts:', error);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async persist() {
|
|
48
|
-
try {
|
|
49
|
-
const trimmedReceipts = this.receipts.slice(-this.maxReceipts);
|
|
50
|
-
await this.storage.set(this.storageKey, trimmedReceipts);
|
|
51
|
-
this.receipts = trimmedReceipts;
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
this.logger.error('Failed to persist receipts:', error);
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
async add(receipt) {
|
|
59
|
-
this.receipts.push(receipt);
|
|
60
|
-
this.logger.debug(`Added receipt: ${receipt.txpowid}`);
|
|
61
|
-
await this.persist();
|
|
62
|
-
}
|
|
63
|
-
getAll() {
|
|
64
|
-
return [...this.receipts].reverse();
|
|
65
|
-
}
|
|
66
|
-
getByTxpowid(txpowid) {
|
|
67
|
-
return this.receipts.find(r => r.txpowid === txpowid);
|
|
68
|
-
}
|
|
69
|
-
getRecent(count = 50) {
|
|
70
|
-
return this.getAll().slice(0, count);
|
|
71
|
-
}
|
|
72
|
-
async updateStatus(txpowid, status) {
|
|
73
|
-
const receipt = this.receipts.find(r => r.txpowid === txpowid);
|
|
74
|
-
if (receipt) {
|
|
75
|
-
receipt.status = status;
|
|
76
|
-
this.logger.debug(`Updated receipt status: ${txpowid} → ${status}`);
|
|
77
|
-
await this.persist();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
async clear() {
|
|
81
|
-
this.receipts = [];
|
|
82
|
-
await this.storage.remove(this.storageKey);
|
|
83
|
-
this.logger.debug('Cleared all receipts');
|
|
84
|
-
}
|
|
85
|
-
count() {
|
|
86
|
-
return this.receipts.length;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
exports.TransactionReceiptStore = TransactionReceiptStore;
|