@ocap/state 1.28.8 → 1.29.0
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/esm/_virtual/rolldown_runtime.mjs +18 -0
- package/esm/contexts/state.d.mts +15 -0
- package/esm/contexts/state.mjs +17 -0
- package/esm/index.d.mts +20 -0
- package/esm/index.mjs +47 -0
- package/esm/states/account.d.mts +18 -0
- package/esm/states/account.mjs +91 -0
- package/esm/states/asset.d.mts +14 -0
- package/esm/states/asset.mjs +80 -0
- package/esm/states/blacklist.d.mts +36 -0
- package/esm/states/blacklist.mjs +71 -0
- package/esm/states/chain.d.mts +30 -0
- package/esm/states/chain.mjs +52 -0
- package/esm/states/delegation.d.mts +11 -0
- package/esm/states/delegation.mjs +42 -0
- package/esm/states/evidence.d.mts +12 -0
- package/esm/states/evidence.mjs +35 -0
- package/esm/states/factory.d.mts +12 -0
- package/esm/states/factory.mjs +76 -0
- package/esm/states/rollup-block.d.mts +13 -0
- package/esm/states/rollup-block.mjs +75 -0
- package/esm/states/rollup.d.mts +18 -0
- package/esm/states/rollup.mjs +215 -0
- package/esm/states/stake.d.mts +13 -0
- package/esm/states/stake.mjs +89 -0
- package/esm/states/token-factory.d.mts +13 -0
- package/esm/states/token-factory.mjs +76 -0
- package/esm/states/token.d.mts +14 -0
- package/esm/states/token.mjs +109 -0
- package/esm/states/tx.d.mts +233 -0
- package/esm/states/tx.mjs +867 -0
- package/esm/util.d.mts +6 -0
- package/esm/util.mjs +18 -0
- package/lib/_virtual/rolldown_runtime.cjs +43 -0
- package/lib/contexts/state.cjs +19 -0
- package/lib/contexts/state.d.cts +15 -0
- package/lib/index.cjs +121 -0
- package/lib/index.d.cts +20 -0
- package/lib/states/account.cjs +106 -0
- package/lib/states/account.d.cts +18 -0
- package/lib/states/asset.cjs +91 -0
- package/lib/states/asset.d.cts +14 -0
- package/lib/states/blacklist.cjs +74 -0
- package/lib/states/blacklist.d.cts +36 -0
- package/lib/states/chain.cjs +62 -0
- package/lib/states/chain.d.cts +30 -0
- package/lib/states/delegation.cjs +50 -0
- package/lib/states/delegation.d.cts +11 -0
- package/lib/states/evidence.cjs +44 -0
- package/lib/states/evidence.d.cts +12 -0
- package/lib/states/factory.cjs +85 -0
- package/lib/states/factory.d.cts +12 -0
- package/lib/states/rollup-block.cjs +85 -0
- package/lib/states/rollup-block.d.cts +13 -0
- package/lib/states/rollup.cjs +230 -0
- package/lib/states/rollup.d.cts +18 -0
- package/lib/states/stake.cjs +99 -0
- package/lib/states/stake.d.cts +13 -0
- package/lib/states/token-factory.cjs +86 -0
- package/lib/states/token-factory.d.cts +13 -0
- package/lib/states/token.cjs +121 -0
- package/lib/states/token.d.cts +14 -0
- package/lib/states/tx.cjs +889 -0
- package/lib/states/tx.d.cts +233 -0
- package/lib/util.cjs +19 -0
- package/lib/util.d.cts +6 -0
- package/package.json +46 -14
- package/lib/contexts/state.js +0 -19
- package/lib/index.js +0 -63
- package/lib/states/account.js +0 -95
- package/lib/states/asset.js +0 -91
- package/lib/states/blacklist.js +0 -103
- package/lib/states/chain.js +0 -49
- package/lib/states/delegation.js +0 -46
- package/lib/states/evidence.js +0 -35
- package/lib/states/factory.js +0 -92
- package/lib/states/rollup-block.js +0 -84
- package/lib/states/rollup.js +0 -297
- package/lib/states/stake.js +0 -83
- package/lib/states/token-factory.js +0 -74
- package/lib/states/token.js +0 -124
- package/lib/states/tx.js +0 -896
- package/lib/util.js +0 -28
package/lib/states/tx.js
DELETED
|
@@ -1,896 +0,0 @@
|
|
|
1
|
-
const get = require('lodash/get');
|
|
2
|
-
const pick = require('lodash/pick');
|
|
3
|
-
const merge = require('lodash/merge');
|
|
4
|
-
const groupBy = require('lodash/groupBy');
|
|
5
|
-
const upperFirst = require('lodash/upperFirst');
|
|
6
|
-
const camelCase = require('lodash/camelCase');
|
|
7
|
-
const { fromTypeUrl, formatMessage, decodeAny } = require('@ocap/message');
|
|
8
|
-
const { toBase64, BN, isBN, fromTokenToUnit } = require('@ocap/util');
|
|
9
|
-
const { getListField } = require('@ocap/util/lib/get-list-field');
|
|
10
|
-
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
11
|
-
const { getRelatedAddresses } = require('@ocap/util/lib/get-related-addr');
|
|
12
|
-
const { toTypeInfo, types } = require('@arcblock/did');
|
|
13
|
-
|
|
14
|
-
const ZERO = new BN(0);
|
|
15
|
-
const { RoleType } = types;
|
|
16
|
-
|
|
17
|
-
const FORGE_TOKEN_HOLDER = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
|
|
18
|
-
const FORGE_FEE_RECEIVER = 'z1EJUBdbPYqMiWHfRZvSAvbYeWcEHB19Xyfc';
|
|
19
|
-
const QLDB_MIGRATION_TIME = new Date('2021-05-03T12:46:56.245Z');
|
|
20
|
-
|
|
21
|
-
function eachReceipts(receipts, callback) {
|
|
22
|
-
const result = (receipts || []).map((receipt) => {
|
|
23
|
-
return (receipt.changes || []).map((change) => callback(receipt.address, change));
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
return result.flat();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function groupReceiptTokenChanges(receipts) {
|
|
30
|
-
/**
|
|
31
|
-
* Map of address to token changes
|
|
32
|
-
* @type {Record<string, {[tokenAddress: string]: string}>}
|
|
33
|
-
*/
|
|
34
|
-
const tokenChanges = {};
|
|
35
|
-
// get token changes for each account by receipts
|
|
36
|
-
eachReceipts(receipts || [], (address, change) => {
|
|
37
|
-
if (toTypeInfo(change.target).role !== RoleType.ROLE_TOKEN) return;
|
|
38
|
-
if (change.value === '0') return;
|
|
39
|
-
if (!tokenChanges[address]) {
|
|
40
|
-
tokenChanges[address] = {};
|
|
41
|
-
}
|
|
42
|
-
const tokenChange = tokenChanges[address];
|
|
43
|
-
tokenChange[change.target] = new BN(tokenChange[change.target] || 0).add(new BN(change.value)).toString();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return tokenChanges;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Receiver = Whose asset have net gain
|
|
50
|
-
const getTxReceiver = ({ tx, itx, typeUrl }) => {
|
|
51
|
-
switch (typeUrl) {
|
|
52
|
-
case 'TransferTx':
|
|
53
|
-
case 'ExchangeTx':
|
|
54
|
-
case 'TransferV2Tx':
|
|
55
|
-
case 'ExchangeV2Tx':
|
|
56
|
-
return itx.to;
|
|
57
|
-
case 'MintAssetTx':
|
|
58
|
-
return itx.owner;
|
|
59
|
-
case 'CreateTokenTx':
|
|
60
|
-
case 'CreateAssetTx':
|
|
61
|
-
case 'AcquireAssetV2Tx':
|
|
62
|
-
return tx.delegator || tx.from;
|
|
63
|
-
case 'AcquireAssetV3Tx':
|
|
64
|
-
return itx.owner;
|
|
65
|
-
case 'SetupSwapTx':
|
|
66
|
-
return itx.receiver;
|
|
67
|
-
case 'StakeTx':
|
|
68
|
-
return itx.address;
|
|
69
|
-
default:
|
|
70
|
-
return '';
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// Sender = Whose asset have net lose
|
|
75
|
-
const getTxSender = ({ tx, typeUrl }) => {
|
|
76
|
-
switch (typeUrl) {
|
|
77
|
-
case 'TransferTx':
|
|
78
|
-
case 'TransferV2Tx':
|
|
79
|
-
case 'ExchangeTx':
|
|
80
|
-
case 'ExchangeV2Tx':
|
|
81
|
-
case 'AcquireAssetV2Tx':
|
|
82
|
-
case 'SetupSwapTx':
|
|
83
|
-
case 'WithdrawTokenTx':
|
|
84
|
-
case 'StakeTx':
|
|
85
|
-
case 'ReturnStakeTx':
|
|
86
|
-
case 'SlashStakeTx':
|
|
87
|
-
return tx.from;
|
|
88
|
-
default:
|
|
89
|
-
return '';
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const getReceiptChange = (receipts, { address, action }) => {
|
|
94
|
-
const receipt = receipts.filter((x) => !address || x.address === address);
|
|
95
|
-
const changes = receipt.flatMap((x) => x.changes.filter((c) => !action || c.action === action));
|
|
96
|
-
return changes;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const getTransferReceipts = (tx) => {
|
|
100
|
-
const senderReceipt = { address: tx.from, changes: [] };
|
|
101
|
-
const receiverReceipt = { address: tx.itxJson.to, changes: [] };
|
|
102
|
-
|
|
103
|
-
if (new BN(tx.itxJson.value).gt(ZERO)) {
|
|
104
|
-
senderReceipt.changes.push({ target: '', action: 'transfer', value: `-${tx.itxJson.value}` });
|
|
105
|
-
receiverReceipt.changes.push({ target: '', action: 'transfer', value: tx.itxJson.value });
|
|
106
|
-
}
|
|
107
|
-
if (Array.isArray(tx.itxJson.tokens)) {
|
|
108
|
-
tx.itxJson.tokens.forEach((x) => {
|
|
109
|
-
senderReceipt.changes.push({ target: x.address, action: 'transfer', value: `-${x.value}` });
|
|
110
|
-
receiverReceipt.changes.push({ target: x.address, action: 'transfer', value: x.value });
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
if (Array.isArray(tx.itxJson.assets)) {
|
|
114
|
-
tx.itxJson.assets.forEach((x) => {
|
|
115
|
-
senderReceipt.changes.push({ target: x, action: 'transfer', value: '-1' });
|
|
116
|
-
receiverReceipt.changes.push({ target: x, action: 'transfer', value: '1' });
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return [senderReceipt, receiverReceipt];
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const getReceiptsFromTxInput = (inputs, symbol, action = 'transfer') => {
|
|
124
|
-
const receipts = [];
|
|
125
|
-
inputs.forEach((x) => {
|
|
126
|
-
const receipt = { address: x.owner, changes: [] };
|
|
127
|
-
getListField(x, 'tokens').forEach(({ address, value }) => {
|
|
128
|
-
receipt.changes.push({ target: address, action, value: `${symbol}${value}` });
|
|
129
|
-
});
|
|
130
|
-
getListField(x, 'assets').forEach((address) =>
|
|
131
|
-
receipt.changes.push({ target: address, action, value: `${symbol}1` })
|
|
132
|
-
);
|
|
133
|
-
receipts.push(receipt);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
return receipts;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
// TODO: this logic does not support assets yet
|
|
140
|
-
const getReceiptsFromContext = (ctx) => {
|
|
141
|
-
if (Array.isArray(ctx.updatedAccounts)) {
|
|
142
|
-
const grouped = groupBy(
|
|
143
|
-
ctx.updatedAccounts.filter((x) => x.address && x.delta),
|
|
144
|
-
'address'
|
|
145
|
-
);
|
|
146
|
-
return Object.keys(grouped).map((k) => ({
|
|
147
|
-
address: k,
|
|
148
|
-
changes: grouped[k].map((x) => ({ target: x.token, action: x.action || 'transfer', value: x.delta })),
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return [];
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Add receipts for tx that have gasPaid but no receipts
|
|
157
|
-
* This is used to handle legacy data that gas receipts were not properly recorded
|
|
158
|
-
*/
|
|
159
|
-
const getReceiptsFromGasPaid = (tx, { config, typeUrl }) => {
|
|
160
|
-
const gasReceipt = getReceiptChange(tx.receipts || [], { action: 'gas' });
|
|
161
|
-
const gasPaid = new BN(tx.gasPaid || 0);
|
|
162
|
-
|
|
163
|
-
// For new transactions being created, gas receipts are usually attached by getReceiptsFromContext before,
|
|
164
|
-
// so we don't add duplicate gas receipts here
|
|
165
|
-
if (gasReceipt.length) return [];
|
|
166
|
-
if (gasPaid.lte(ZERO)) return [];
|
|
167
|
-
|
|
168
|
-
const gasPayerMap = {
|
|
169
|
-
AccountMigrateTx: tx.itxJson?.address,
|
|
170
|
-
};
|
|
171
|
-
const gasPayer = gasPayerMap[typeUrl] || tx.from;
|
|
172
|
-
// Cannot determine who received the gas fee in legacy data
|
|
173
|
-
const gasReceiver = config?.vaults?.txGas?.[0] || FORGE_FEE_RECEIVER;
|
|
174
|
-
|
|
175
|
-
if (!gasPayer) return [];
|
|
176
|
-
|
|
177
|
-
return [
|
|
178
|
-
{ address: gasPayer, changes: [{ target: '', action: 'gas', value: gasPaid.neg().toString() }] },
|
|
179
|
-
{ address: gasReceiver, changes: [{ target: '', action: 'gas', value: gasPaid.toString() }] },
|
|
180
|
-
];
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
const getTransferV3Receipts = (tx) => [
|
|
184
|
-
...getReceiptsFromTxInput(tx.itxJson.inputs, '-', 'transfer'),
|
|
185
|
-
...getReceiptsFromTxInput(tx.itxJson.outputs, '', 'transfer'),
|
|
186
|
-
];
|
|
187
|
-
|
|
188
|
-
const getExchangeReceipts = (tx, ctx) => {
|
|
189
|
-
const { senderState, receiverState } = ctx;
|
|
190
|
-
const { sender, receiver } = tx.itxJson;
|
|
191
|
-
const senderReceipt = { address: senderState ? senderState.address : tx.from, changes: [] };
|
|
192
|
-
const receiverReceipt = { address: receiverState ? receiverState.address : tx.itxJson.to, changes: [] };
|
|
193
|
-
|
|
194
|
-
if (new BN(sender.value).gt(ZERO)) {
|
|
195
|
-
senderReceipt.changes.push({ target: '', action: 'transfer', value: `-${sender.value}` });
|
|
196
|
-
receiverReceipt.changes.push({ target: '', action: 'transfer', value: sender.value });
|
|
197
|
-
}
|
|
198
|
-
if (new BN(receiver.value).gt(ZERO)) {
|
|
199
|
-
receiverReceipt.changes.push({ target: '', action: 'transfer', value: `-${receiver.value}` });
|
|
200
|
-
senderReceipt.changes.push({ target: '', action: 'transfer', value: receiver.value });
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (Array.isArray(sender.tokens)) {
|
|
204
|
-
sender.tokens.forEach((x) => {
|
|
205
|
-
senderReceipt.changes.push({ target: x.address, action: 'transfer', value: `-${x.value}` });
|
|
206
|
-
receiverReceipt.changes.push({ target: x.address, action: 'transfer', value: x.value });
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
if (Array.isArray(receiver.tokens)) {
|
|
210
|
-
receiver.tokens.forEach((x) => {
|
|
211
|
-
receiverReceipt.changes.push({ target: x.address, action: 'transfer', value: `-${x.value}` });
|
|
212
|
-
senderReceipt.changes.push({ target: x.address, action: 'transfer', value: x.value });
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (Array.isArray(sender.assets)) {
|
|
217
|
-
sender.assets.forEach((x) => {
|
|
218
|
-
senderReceipt.changes.push({ target: x, action: 'transfer', value: '-1' });
|
|
219
|
-
receiverReceipt.changes.push({ target: x, action: 'transfer', value: '1' });
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
if (Array.isArray(receiver.assets)) {
|
|
223
|
-
receiver.assets.forEach((x) => {
|
|
224
|
-
receiverReceipt.changes.push({ target: x, action: 'transfer', value: '-1' });
|
|
225
|
-
senderReceipt.changes.push({ target: x, action: 'transfer', value: '1' });
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return [senderReceipt, receiverReceipt];
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
const getCreateAssetReceipts = (tx) => {
|
|
233
|
-
const owner = tx.delegator || tx.from;
|
|
234
|
-
const ownerReceipt = { address: owner, changes: [{ target: tx.itxJson.address, action: 'create', value: '1' }] };
|
|
235
|
-
return [ownerReceipt];
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
const getMintAssetReceipts = (tx, ctx) => {
|
|
239
|
-
const { assets = [], address, owner } = tx.itxJson;
|
|
240
|
-
const ownerReceipt = {
|
|
241
|
-
address: ctx.ownerAddress || owner,
|
|
242
|
-
changes: [{ target: address, action: 'mint', value: '1' }],
|
|
243
|
-
};
|
|
244
|
-
assets.map((x) => ownerReceipt.changes.push({ target: x, action: 'consume', value: '-1' }));
|
|
245
|
-
return [ownerReceipt];
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
const getAcquireAssetReceipts = (tx, ctx) => {
|
|
249
|
-
const { assets = [], address } = tx.itxJson;
|
|
250
|
-
const delegator = tx.delegator || tx.from;
|
|
251
|
-
|
|
252
|
-
const ownerReceipt = { address: delegator, changes: [{ target: address, action: 'mint', value: '1' }] }; // who owns the minted asset
|
|
253
|
-
const senderReceipt = { address: tx.from, changes: [] }; // who paid for this tx
|
|
254
|
-
|
|
255
|
-
assets.map((x) => senderReceipt.changes.push({ target: x, action: 'consume', value: '-1' }));
|
|
256
|
-
|
|
257
|
-
if (ctx.factoryState) {
|
|
258
|
-
const { value, tokens } = ctx.factoryState.input;
|
|
259
|
-
if (new BN(value).gt(ZERO)) {
|
|
260
|
-
senderReceipt.changes.push({ target: '', action: 'consume', value: `-${value}` });
|
|
261
|
-
}
|
|
262
|
-
tokens.map((x) => senderReceipt.changes.push({ target: x.address, action: 'consume', value: `-${x.value}` }));
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
let mergedReceipts = [ownerReceipt, senderReceipt];
|
|
266
|
-
if (ownerReceipt.address === senderReceipt.address) {
|
|
267
|
-
senderReceipt.changes = [...ownerReceipt.changes, ...senderReceipt.changes];
|
|
268
|
-
mergedReceipts = [senderReceipt];
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return [...mergedReceipts];
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
const getAcquireAssetV3Receipts = (tx) => {
|
|
275
|
-
const { inputs, owner, address } = tx.itxJson;
|
|
276
|
-
const ownerReceipt = { address: owner, changes: [{ target: address, action: 'mint', value: '1' }] };
|
|
277
|
-
return [ownerReceipt, ...getReceiptsFromTxInput(inputs, '-', 'consume')];
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const getStakeReceipts = (tx) => {
|
|
281
|
-
const { inputs, address } = tx.itxJson;
|
|
282
|
-
|
|
283
|
-
// aggregated stake changes
|
|
284
|
-
const tokens = {};
|
|
285
|
-
const assets = [];
|
|
286
|
-
inputs.forEach((input) => {
|
|
287
|
-
input.tokens.forEach((x) => {
|
|
288
|
-
if (typeof tokens[x.address] === 'undefined') {
|
|
289
|
-
tokens[x.address] = new BN(0);
|
|
290
|
-
}
|
|
291
|
-
tokens[x.address] = tokens[x.address].add(new BN(x.value));
|
|
292
|
-
});
|
|
293
|
-
assets.push(...input.assets);
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
const stakeReceipt = { address, changes: [] };
|
|
297
|
-
assets.forEach((x) => stakeReceipt.changes.push({ target: x, action: 'stake', value: '1' }));
|
|
298
|
-
Object.keys(tokens).forEach((x) =>
|
|
299
|
-
stakeReceipt.changes.push({ target: x, action: 'stake', value: tokens[x].toString(10) })
|
|
300
|
-
);
|
|
301
|
-
|
|
302
|
-
return [stakeReceipt, ...getReceiptsFromTxInput(inputs, '-', 'stake')];
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
const getClaimStakeReceipts = (tx, ctx, action) => {
|
|
306
|
-
const { address } = tx.itxJson;
|
|
307
|
-
const { outputs } = ctx;
|
|
308
|
-
|
|
309
|
-
// aggregated stake changes
|
|
310
|
-
const tokens = {};
|
|
311
|
-
const assets = [];
|
|
312
|
-
outputs.forEach((output) => {
|
|
313
|
-
getListField(output, 'tokens').forEach((x) => {
|
|
314
|
-
if (typeof tokens[x.address] === 'undefined') {
|
|
315
|
-
tokens[x.address] = new BN(0);
|
|
316
|
-
}
|
|
317
|
-
tokens[x.address] = tokens[x.address].add(new BN(x.value));
|
|
318
|
-
});
|
|
319
|
-
assets.push(...getListField(output, 'assets'));
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
const stakeReceipt = { address, changes: [] };
|
|
323
|
-
assets.forEach((x) => stakeReceipt.changes.push({ target: x, action, value: '-1' }));
|
|
324
|
-
Object.keys(tokens).forEach((x) =>
|
|
325
|
-
stakeReceipt.changes.push({ target: x, action, value: `-${tokens[x].toString(10)}` })
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
return [stakeReceipt, ...getReceiptsFromTxInput(outputs, '', action)];
|
|
329
|
-
};
|
|
330
|
-
|
|
331
|
-
const getCreateTokenReceipts = (tx) => {
|
|
332
|
-
const { initialSupply, address } = tx.itxJson;
|
|
333
|
-
const balance = new BN(initialSupply).toString();
|
|
334
|
-
|
|
335
|
-
const issuerReceipt = {
|
|
336
|
-
address: tx.delegator || tx.from,
|
|
337
|
-
changes: [{ target: address, action: 'mint', value: balance }],
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
return [issuerReceipt];
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
const getMintTokenReceipts = (tx, ctx) => {
|
|
344
|
-
const { inputChanges, tokenFactoryState } = ctx;
|
|
345
|
-
const { reserveAddress, tokenAddress, owner } = tokenFactoryState;
|
|
346
|
-
const hasFee = new BN(ctx.reserveFee || '0').gt(ZERO);
|
|
347
|
-
|
|
348
|
-
const inputReceipts = inputChanges.map((input) => {
|
|
349
|
-
return {
|
|
350
|
-
address: input.address,
|
|
351
|
-
changes: [
|
|
352
|
-
{
|
|
353
|
-
target: reserveAddress,
|
|
354
|
-
action: 'swap',
|
|
355
|
-
value: input.delta,
|
|
356
|
-
},
|
|
357
|
-
],
|
|
358
|
-
};
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
return inputReceipts
|
|
362
|
-
.concat([
|
|
363
|
-
{
|
|
364
|
-
address: tx.itxJson.receiver,
|
|
365
|
-
changes: [
|
|
366
|
-
{
|
|
367
|
-
target: tokenAddress,
|
|
368
|
-
action: 'mint',
|
|
369
|
-
value: `${tx.itxJson.amount}`,
|
|
370
|
-
},
|
|
371
|
-
],
|
|
372
|
-
},
|
|
373
|
-
])
|
|
374
|
-
.concat(
|
|
375
|
-
hasFee
|
|
376
|
-
? [
|
|
377
|
-
{
|
|
378
|
-
address: owner,
|
|
379
|
-
changes: [{ target: reserveAddress, action: 'fee', value: `${ctx.reserveFee}` }],
|
|
380
|
-
},
|
|
381
|
-
]
|
|
382
|
-
: []
|
|
383
|
-
);
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
const getBurnTokenReceipts = (tx, ctx) => {
|
|
387
|
-
const { inputChanges, tokenFactoryState } = ctx;
|
|
388
|
-
const { reserveAddress, tokenAddress, owner } = tokenFactoryState;
|
|
389
|
-
|
|
390
|
-
const fee = new BN(ctx.reserveFee || '0');
|
|
391
|
-
const receiveAmount = new BN(ctx.reserveAmount || '0').sub(fee);
|
|
392
|
-
|
|
393
|
-
const inputReceipts = inputChanges.map((input) => {
|
|
394
|
-
return {
|
|
395
|
-
address: input.address,
|
|
396
|
-
changes: [
|
|
397
|
-
{
|
|
398
|
-
target: tokenAddress,
|
|
399
|
-
action: 'burn',
|
|
400
|
-
value: input.delta,
|
|
401
|
-
},
|
|
402
|
-
],
|
|
403
|
-
};
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
return inputReceipts
|
|
407
|
-
.concat(
|
|
408
|
-
receiveAmount.gt(ZERO)
|
|
409
|
-
? [
|
|
410
|
-
{
|
|
411
|
-
address: tx.itxJson.receiver,
|
|
412
|
-
changes: [{ target: reserveAddress, action: 'swap', value: receiveAmount.toString() }],
|
|
413
|
-
},
|
|
414
|
-
]
|
|
415
|
-
: []
|
|
416
|
-
)
|
|
417
|
-
.concat(
|
|
418
|
-
fee.gt(ZERO)
|
|
419
|
-
? [
|
|
420
|
-
{
|
|
421
|
-
address: owner,
|
|
422
|
-
changes: [{ target: reserveAddress, action: 'fee', value: fee.toString() }],
|
|
423
|
-
},
|
|
424
|
-
]
|
|
425
|
-
: []
|
|
426
|
-
);
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
// Following only exist for legacy support purpose
|
|
430
|
-
const getDepositTokenReceipts = (tx) => [
|
|
431
|
-
{
|
|
432
|
-
address: tx.itxJson.address,
|
|
433
|
-
changes: [{ target: '', action: 'mint', value: tx.itxJson.value }],
|
|
434
|
-
},
|
|
435
|
-
];
|
|
436
|
-
|
|
437
|
-
const getWithdrawFee = (value) => {
|
|
438
|
-
let fee = new BN(value).abs().mul(new BN('1')).div(new BN('1000')); // 0.1% fee
|
|
439
|
-
fee = BN.min(fee, new BN('100000000000000000000')); // max 100 ABT
|
|
440
|
-
fee = BN.max(fee, new BN('1000000000000000000')); // min 1 ABT
|
|
441
|
-
return fee;
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
const getWithdrawTokenReceipts = (tx) => {
|
|
445
|
-
const fee = getWithdrawFee(tx.itxJson.value);
|
|
446
|
-
|
|
447
|
-
return [
|
|
448
|
-
{
|
|
449
|
-
address: tx.from,
|
|
450
|
-
changes: [
|
|
451
|
-
{ target: '', action: 'lock', value: `-${tx.itxJson.value}` },
|
|
452
|
-
{ target: '', action: 'fee', value: `-${fee.toString()}` },
|
|
453
|
-
],
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
address: FORGE_TOKEN_HOLDER,
|
|
457
|
-
changes: [
|
|
458
|
-
{ target: '', action: 'lock', value: tx.itxJson.value },
|
|
459
|
-
{ target: '', action: 'fee', value: fee.toString() },
|
|
460
|
-
],
|
|
461
|
-
},
|
|
462
|
-
];
|
|
463
|
-
};
|
|
464
|
-
|
|
465
|
-
const getRevokeWithdrawReceipts = (tx, { withdrawTx }) => {
|
|
466
|
-
if (!withdrawTx?.tx?.from) return [];
|
|
467
|
-
if (withdrawTx.hash !== tx.itxJson.withdraw_tx_hash) return [];
|
|
468
|
-
|
|
469
|
-
const account = withdrawTx.tx.from;
|
|
470
|
-
const withdrawReceipt = withdrawTx.receipts?.find((x) => x.address === account);
|
|
471
|
-
const lockChange = withdrawReceipt?.changes?.find((x) => x.action === 'lock');
|
|
472
|
-
|
|
473
|
-
if (!lockChange) return [];
|
|
474
|
-
|
|
475
|
-
const value = new BN(lockChange.value).abs();
|
|
476
|
-
const fee = getWithdrawFee(value.toString());
|
|
477
|
-
const revokeFee = fee.mul(new BN('5')).div(new BN('100')); // 5% fee
|
|
478
|
-
|
|
479
|
-
return [
|
|
480
|
-
{
|
|
481
|
-
address: account,
|
|
482
|
-
changes: [
|
|
483
|
-
{ target: '', action: 'unlock', value: value.toString() },
|
|
484
|
-
{ target: '', action: 'fee', value: fee.sub(revokeFee).toString() },
|
|
485
|
-
],
|
|
486
|
-
},
|
|
487
|
-
{
|
|
488
|
-
address: FORGE_TOKEN_HOLDER,
|
|
489
|
-
changes: [
|
|
490
|
-
{ target: '', action: 'unlock', value: `-${value.toString()}` },
|
|
491
|
-
{ target: '', action: 'fee', value: `-${fee.toString()}` },
|
|
492
|
-
],
|
|
493
|
-
},
|
|
494
|
-
{
|
|
495
|
-
address: FORGE_FEE_RECEIVER,
|
|
496
|
-
changes: [{ target: '', action: 'fee', value: revokeFee.toString() }],
|
|
497
|
-
},
|
|
498
|
-
];
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
const getApproveWithdrawReceipts = (tx, { withdrawTx }) => {
|
|
502
|
-
if (!withdrawTx?.tx?.itxJson?.value) return [];
|
|
503
|
-
if (withdrawTx.hash !== tx.itxJson.withdraw_tx_hash) return [];
|
|
504
|
-
|
|
505
|
-
const { value } = withdrawTx.tx.itxJson;
|
|
506
|
-
const fee = getWithdrawFee(value);
|
|
507
|
-
|
|
508
|
-
return [
|
|
509
|
-
{
|
|
510
|
-
address: FORGE_TOKEN_HOLDER,
|
|
511
|
-
changes: [
|
|
512
|
-
{ target: '', action: 'burn', value: `-${value}` },
|
|
513
|
-
{ target: '', action: 'fee', value: `-${fee.toString()}` },
|
|
514
|
-
],
|
|
515
|
-
},
|
|
516
|
-
{
|
|
517
|
-
address: FORGE_FEE_RECEIVER,
|
|
518
|
-
changes: [{ target: '', action: 'fee', value: fee.toString() }],
|
|
519
|
-
},
|
|
520
|
-
];
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
const getSetupSwapReceipts = (tx) => [
|
|
524
|
-
{
|
|
525
|
-
address: tx.from,
|
|
526
|
-
changes: [
|
|
527
|
-
new BN(tx.itxJson.value).gt(ZERO) ? { target: '', action: 'swap', value: `-${tx.itxJson.value}` } : null,
|
|
528
|
-
...tx.itxJson.assets.map((x) => ({
|
|
529
|
-
target: x,
|
|
530
|
-
action: 'swap',
|
|
531
|
-
value: '-1',
|
|
532
|
-
})),
|
|
533
|
-
].filter(Boolean),
|
|
534
|
-
},
|
|
535
|
-
];
|
|
536
|
-
const getRetrieveSwapReceipts = (tx) => [
|
|
537
|
-
{
|
|
538
|
-
address: tx.from,
|
|
539
|
-
changes: [
|
|
540
|
-
new BN(tx.itxJson.value).gt(ZERO) ? { target: '', action: 'swap', value: tx.itxJson.value } : null,
|
|
541
|
-
...tx.itxJson.assets.map((x) => ({
|
|
542
|
-
target: x,
|
|
543
|
-
action: 'swap',
|
|
544
|
-
value: '1',
|
|
545
|
-
})),
|
|
546
|
-
].filter(Boolean),
|
|
547
|
-
},
|
|
548
|
-
];
|
|
549
|
-
|
|
550
|
-
const getMigrateReceipts = (tx, context) => {
|
|
551
|
-
const fromState = context.fromState || context.senderState;
|
|
552
|
-
|
|
553
|
-
if (!fromState?.tokens) return [];
|
|
554
|
-
if (!tx.itxJson?.address) return [];
|
|
555
|
-
|
|
556
|
-
const changes = Object.entries(fromState.tokens)
|
|
557
|
-
.filter(([, value]) => value && value !== '0')
|
|
558
|
-
.map(([address, value]) => ({ target: address, action: 'migrate', value }));
|
|
559
|
-
|
|
560
|
-
return changes.length
|
|
561
|
-
? [
|
|
562
|
-
{
|
|
563
|
-
address: tx.itxJson.address,
|
|
564
|
-
changes,
|
|
565
|
-
},
|
|
566
|
-
]
|
|
567
|
-
: [];
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
const getDeclareReceipts = (tx, { config, time }) => {
|
|
571
|
-
const txTime = new Date(time);
|
|
572
|
-
|
|
573
|
-
if (!tx.itxJson?.issuer) return [];
|
|
574
|
-
if (!config?.token) return [];
|
|
575
|
-
if (!time) return [];
|
|
576
|
-
if (txTime >= QLDB_MIGRATION_TIME) return [];
|
|
577
|
-
|
|
578
|
-
const gas = fromTokenToUnit('0.5', config.token.decimal);
|
|
579
|
-
|
|
580
|
-
return [
|
|
581
|
-
{
|
|
582
|
-
address: tx.itxJson?.issuer,
|
|
583
|
-
changes: [{ target: config.token.address, action: 'gas', value: `-${gas.toString()}` }],
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
address: FORGE_FEE_RECEIVER,
|
|
587
|
-
changes: [{ target: config.token.address, action: 'gas', value: gas.toString() }],
|
|
588
|
-
},
|
|
589
|
-
];
|
|
590
|
-
};
|
|
591
|
-
|
|
592
|
-
const mergeTxReceipts = (receipts) => {
|
|
593
|
-
const merged = [];
|
|
594
|
-
receipts.forEach((x) => {
|
|
595
|
-
if (merged[x.address] === undefined) {
|
|
596
|
-
merged[x.address] = x;
|
|
597
|
-
} else {
|
|
598
|
-
merged[x.address].changes = [...merged[x.address].changes, ...x.changes];
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
return Object.values(merged);
|
|
603
|
-
};
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* Get list of accounts with migration history
|
|
607
|
-
* @param {Object} ctx - transaction execution context
|
|
608
|
-
* @returns {Promise<string[][]>} adress[][]
|
|
609
|
-
*/
|
|
610
|
-
const getAccountMigrationsFromContext = (ctx) => {
|
|
611
|
-
const migrationAddresses = [];
|
|
612
|
-
for (const [key, state] of Object.entries(ctx)) {
|
|
613
|
-
if (key.endsWith('State') && state?.address) {
|
|
614
|
-
migrationAddresses.push(getRelatedAddresses(state));
|
|
615
|
-
}
|
|
616
|
-
if (key.endsWith('States') && Array.isArray(state)) {
|
|
617
|
-
state.forEach((x) => {
|
|
618
|
-
if (x?.address) {
|
|
619
|
-
migrationAddresses.push(getRelatedAddresses(x));
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
return migrationAddresses;
|
|
625
|
-
};
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Group receipts by target
|
|
629
|
-
* @param {Object[]} receipts - transaction receipts
|
|
630
|
-
* @returns {Record<string, { address: string, value: BN, action: string }[]>}
|
|
631
|
-
*/
|
|
632
|
-
const groupReceiptsByTarget = (receipts) => {
|
|
633
|
-
const targets = {};
|
|
634
|
-
|
|
635
|
-
for (const { address, changes } of receipts) {
|
|
636
|
-
for (const { target, value, action } of changes) {
|
|
637
|
-
if (!targets[target]) {
|
|
638
|
-
targets[target] = [];
|
|
639
|
-
}
|
|
640
|
-
targets[target].push({ address, value: new BN(value), action });
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
return targets;
|
|
644
|
-
};
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Verify transaction receipts
|
|
648
|
-
* @param {Object[]} receipts - transaction receipts
|
|
649
|
-
* @param {String} typeUrl - transaction type
|
|
650
|
-
* @param {Object} ctx - transaction execution context
|
|
651
|
-
* @returns {Promise<boolean>}
|
|
652
|
-
*/
|
|
653
|
-
const verifyTxReceipts = (receipts, typeUrl, ctx = {}) => {
|
|
654
|
-
const targets = groupReceiptsByTarget(receipts);
|
|
655
|
-
const accountsWithMigration = getAccountMigrationsFromContext(ctx);
|
|
656
|
-
const skipActions =
|
|
657
|
-
{
|
|
658
|
-
MintAssetTx: ['mint', 'consume'],
|
|
659
|
-
AcquireAssetV2Tx: ['mint', 'consume'],
|
|
660
|
-
AcquireAssetV3Tx: ['mint', 'consume'],
|
|
661
|
-
CreateAssetTx: ['create'],
|
|
662
|
-
CreateTokenTx: ['mint'],
|
|
663
|
-
CreateRollupBlockTx: ['burn', 'mint'],
|
|
664
|
-
AccountMigrateTx: ['migrate'],
|
|
665
|
-
ApproveWithdrawTx: ['burn'],
|
|
666
|
-
SetupSwapTx: ['swap'],
|
|
667
|
-
RevokeSwapTx: ['swap'],
|
|
668
|
-
RetrieveSwapTx: ['swap'],
|
|
669
|
-
MintTokenTx: ['swap', 'mint', 'fee'],
|
|
670
|
-
BurnTokenTx: ['burn', 'swap', 'fee'],
|
|
671
|
-
}[typeUrl] || [];
|
|
672
|
-
|
|
673
|
-
for (const [target, changes] of Object.entries(targets)) {
|
|
674
|
-
// These actions will skip zero-sum calculation
|
|
675
|
-
const filteredChanges = changes.filter(({ action }) => {
|
|
676
|
-
if (!skipActions.includes(action)) return true;
|
|
677
|
-
if (action === 'consume' && toTypeInfo(target).role !== RoleType.ROLE_ASSET) return true;
|
|
678
|
-
return false;
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
// Ensure token/asset amounts are zero-sum
|
|
682
|
-
const sum = filteredChanges.reduce((prev, current) => prev.add(current.value), new BN(0));
|
|
683
|
-
if (!sum.eq(ZERO)) {
|
|
684
|
-
throw new Error('INVALID_RECEIPTS_VALUE', `Receipts are not zero-sum, target: ${target}, sum: ${sum}`);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// Ensure address is unique
|
|
688
|
-
const accountValue = {};
|
|
689
|
-
for (const { address, value, action } of filteredChanges) {
|
|
690
|
-
const accounts = accountsWithMigration.find((x) => x.includes(address)) || [address];
|
|
691
|
-
for (const account of accounts) {
|
|
692
|
-
const key = `${action}-${account}`;
|
|
693
|
-
const existingValue = accountValue[key];
|
|
694
|
-
if (
|
|
695
|
-
existingValue &&
|
|
696
|
-
((existingValue.gt(ZERO) && value.lt(ZERO)) || (existingValue.lt(ZERO) && value.gt(ZERO)))
|
|
697
|
-
) {
|
|
698
|
-
throw new Error(
|
|
699
|
-
'INVALID_RECEIPTS_ADDRESS',
|
|
700
|
-
`Duplicate accounts in receipts, target: ${target}, address: ${address}, action: ${action}`
|
|
701
|
-
);
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
accountValue[key] = value;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
return true;
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
/**
|
|
713
|
-
* Create transaction receipts, each receipt has following properties:
|
|
714
|
-
*
|
|
715
|
-
* - address: the entity did that changed
|
|
716
|
-
* - changes:
|
|
717
|
-
* - target: the target address that was changed, can be token address, asset address
|
|
718
|
-
* - action: why the target has changed, such as consume, burn and transfer
|
|
719
|
-
* - value: the amount that has changed
|
|
720
|
-
*
|
|
721
|
-
* @param {Object} tx - decoded transaction
|
|
722
|
-
* @param {Object} ctx - transaction execution context
|
|
723
|
-
* @return {Array} list of receipts
|
|
724
|
-
*/
|
|
725
|
-
const getTxReceipts = ({ tx, code }, ctx = {}) => {
|
|
726
|
-
const typeUrl = upperFirst(camelCase(tx?.itxJson?._type || ''));
|
|
727
|
-
|
|
728
|
-
if (code !== 'OK') {
|
|
729
|
-
const receiptsFromContext = ctx.gasPaid ? getReceiptsFromContext(ctx) : [];
|
|
730
|
-
const receiptsFromGas = getReceiptsFromGasPaid(tx, { ...ctx, typeUrl });
|
|
731
|
-
return receiptsFromContext.concat(receiptsFromGas);
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
let receipts = Array.isArray(ctx.receipts) ? ctx.receipts : [];
|
|
735
|
-
|
|
736
|
-
if (['TransferTx', 'TransferV2Tx'].includes(typeUrl)) {
|
|
737
|
-
receipts = receipts.concat(getTransferReceipts(tx, ctx));
|
|
738
|
-
} else if (['TransferV3Tx'].includes(typeUrl)) {
|
|
739
|
-
receipts = receipts.concat(getTransferV3Receipts(tx, ctx));
|
|
740
|
-
} else if (['ExchangeTx', 'ExchangeV2Tx'].includes(typeUrl)) {
|
|
741
|
-
receipts = receipts.concat(getExchangeReceipts(tx, ctx));
|
|
742
|
-
} else if (['CreateAssetTx'].includes(typeUrl)) {
|
|
743
|
-
receipts = receipts.concat(getCreateAssetReceipts(tx, ctx));
|
|
744
|
-
} else if (['MintAssetTx'].includes(typeUrl)) {
|
|
745
|
-
receipts = receipts.concat(getMintAssetReceipts(tx, ctx));
|
|
746
|
-
} else if (['AcquireAssetV2Tx'].includes(typeUrl)) {
|
|
747
|
-
receipts = receipts.concat(getAcquireAssetReceipts(tx, ctx));
|
|
748
|
-
} else if (['AcquireAssetV3Tx'].includes(typeUrl)) {
|
|
749
|
-
receipts = receipts.concat(getAcquireAssetV3Receipts(tx, ctx));
|
|
750
|
-
} else if (['CreateTokenTx'].includes(typeUrl)) {
|
|
751
|
-
receipts = receipts.concat(getCreateTokenReceipts(tx, ctx));
|
|
752
|
-
} else if (['MintTokenTx'].includes(typeUrl)) {
|
|
753
|
-
receipts = receipts.concat(getMintTokenReceipts(tx, ctx));
|
|
754
|
-
} else if (['BurnTokenTx'].includes(typeUrl)) {
|
|
755
|
-
receipts = receipts.concat(getBurnTokenReceipts(tx, ctx));
|
|
756
|
-
} else if (['DepositTokenTx'].includes(typeUrl)) {
|
|
757
|
-
receipts = receipts.concat(getDepositTokenReceipts(tx, ctx));
|
|
758
|
-
} else if (['WithdrawTokenTx'].includes(typeUrl)) {
|
|
759
|
-
receipts = receipts.concat(getWithdrawTokenReceipts(tx, ctx));
|
|
760
|
-
} else if (['SetupSwapTx'].includes(typeUrl)) {
|
|
761
|
-
receipts = receipts.concat(getSetupSwapReceipts(tx, ctx));
|
|
762
|
-
} else if (['RetrieveSwapTx', 'RevokeSwapTx'].includes(typeUrl)) {
|
|
763
|
-
receipts = receipts.concat(getRetrieveSwapReceipts(tx, ctx));
|
|
764
|
-
} else if (['StakeTx'].includes(typeUrl)) {
|
|
765
|
-
receipts = receipts.concat(getStakeReceipts(tx, ctx));
|
|
766
|
-
} else if (['ClaimStakeTx'].includes(typeUrl)) {
|
|
767
|
-
receipts = receipts.concat(getClaimStakeReceipts(tx, ctx, 'claim'));
|
|
768
|
-
} else if (['SlashStakeTx'].includes(typeUrl)) {
|
|
769
|
-
receipts = receipts.concat(getClaimStakeReceipts(tx, ctx, 'slash'));
|
|
770
|
-
} else if (['ReturnStakeTx'].includes(typeUrl)) {
|
|
771
|
-
receipts = receipts.concat(getClaimStakeReceipts(tx, ctx, 'stake'));
|
|
772
|
-
} else if (['RevokeWithdrawTx'].includes(typeUrl)) {
|
|
773
|
-
receipts = receipts.concat(getRevokeWithdrawReceipts(tx, ctx));
|
|
774
|
-
} else if (['ApproveWithdrawTx'].includes(typeUrl)) {
|
|
775
|
-
receipts = receipts.concat(getApproveWithdrawReceipts(tx, ctx));
|
|
776
|
-
} else if (['AccountMigrateTx'].includes(typeUrl)) {
|
|
777
|
-
receipts = receipts.concat(getMigrateReceipts(tx, ctx));
|
|
778
|
-
} else if (['DeclareTx'].includes(typeUrl)) {
|
|
779
|
-
receipts = receipts.concat(getDeclareReceipts(tx, ctx));
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
receipts = receipts.concat(getReceiptsFromContext(ctx));
|
|
783
|
-
receipts = receipts.concat(getReceiptsFromGasPaid(tx, { ...ctx, typeUrl }));
|
|
784
|
-
|
|
785
|
-
const merged = mergeTxReceipts(receipts).filter((x) => x.address && Array.isArray(x.changes) && x.changes.length);
|
|
786
|
-
|
|
787
|
-
// Attach default token address
|
|
788
|
-
const tokenAddr = get(ctx, 'config.token.address', '');
|
|
789
|
-
if (tokenAddr) {
|
|
790
|
-
merged.forEach((x) =>
|
|
791
|
-
x.changes.forEach((c) => {
|
|
792
|
-
if (c.target === '') {
|
|
793
|
-
c.target = tokenAddr;
|
|
794
|
-
}
|
|
795
|
-
})
|
|
796
|
-
);
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
return merged;
|
|
800
|
-
};
|
|
801
|
-
|
|
802
|
-
const create = (context, code = 'OK', verifyReceipts = true) => {
|
|
803
|
-
const { txHash, txTime, tx, totalGas, itxExtras = {}, extra = {} } = context;
|
|
804
|
-
const itx = decodeAny(tx.itx).value; // we should decode here because `context.itx` maybe changed
|
|
805
|
-
const typeUrl = fromTypeUrl(tx.itx.typeUrl);
|
|
806
|
-
const typeName = tx.itx.typeUrl.split(':').pop();
|
|
807
|
-
const itxJson = formatMessage(typeUrl, itx);
|
|
808
|
-
|
|
809
|
-
const result = {
|
|
810
|
-
code,
|
|
811
|
-
hash: txHash,
|
|
812
|
-
height: 0,
|
|
813
|
-
index: 0,
|
|
814
|
-
time: txTime,
|
|
815
|
-
sender: getTxSender({ tx, itx, typeUrl }),
|
|
816
|
-
receiver: getTxReceiver({ tx, itx, typeUrl }),
|
|
817
|
-
type: typeName,
|
|
818
|
-
tx: {
|
|
819
|
-
chainId: tx.chainId,
|
|
820
|
-
delegator: tx.delegator,
|
|
821
|
-
from: tx.from,
|
|
822
|
-
nonce: tx.nonce,
|
|
823
|
-
serviceFee: tx.serviceFee || '0',
|
|
824
|
-
gasFee: isBN(totalGas) ? totalGas.toString(10) : '0',
|
|
825
|
-
pk: toBase64(tx.pk),
|
|
826
|
-
signature: toBase64(tx.signature),
|
|
827
|
-
signatures: getListField(tx, 'signatures').map((x) => formatMessage('Multisig', x)),
|
|
828
|
-
itx: {
|
|
829
|
-
// Hack: this is required because of required by interface type inference on graphql
|
|
830
|
-
__typename: typeUrl,
|
|
831
|
-
},
|
|
832
|
-
itxJson: {
|
|
833
|
-
_type: typeUrl,
|
|
834
|
-
encoded_value: tx.itx.value,
|
|
835
|
-
type_url: tx.itx.typeUrl,
|
|
836
|
-
...itxJson,
|
|
837
|
-
...itxExtras,
|
|
838
|
-
data: itx.data || null,
|
|
839
|
-
},
|
|
840
|
-
extra: extra.txExtra || null,
|
|
841
|
-
},
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
result.receipts = getTxReceipts(result, context);
|
|
845
|
-
|
|
846
|
-
if (code === 'OK' && verifyReceipts) {
|
|
847
|
-
try {
|
|
848
|
-
verifyTxReceipts(result.receipts, typeUrl, context);
|
|
849
|
-
result.receiptsVerified = true;
|
|
850
|
-
} catch (err) {
|
|
851
|
-
console.warn(JSON.stringify(result, null));
|
|
852
|
-
console.error('verifyTxReceipts error', err);
|
|
853
|
-
result.receiptsVerified = false;
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
// determine gasPaid
|
|
858
|
-
attachPaidTxGas(result);
|
|
859
|
-
|
|
860
|
-
return result;
|
|
861
|
-
};
|
|
862
|
-
|
|
863
|
-
const attachPaidTxGas = (tx) => {
|
|
864
|
-
if (tx.tx.gasPaid) {
|
|
865
|
-
return tx;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// determine gasPaid
|
|
869
|
-
let gasChange = null;
|
|
870
|
-
tx.receipts.forEach((r) => {
|
|
871
|
-
const tmp = r.changes.find((c) => c.action === 'gas' && c.value === tx.tx.gasFee);
|
|
872
|
-
if (tmp) {
|
|
873
|
-
gasChange = tmp;
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
tx.tx.gasPaid = gasChange ? tx.tx.gasFee : '0';
|
|
877
|
-
|
|
878
|
-
return tx;
|
|
879
|
-
};
|
|
880
|
-
|
|
881
|
-
// Only a few props are allowed to be changed in tx state
|
|
882
|
-
const update = (state, updates) => merge(state, pick(updates, ['finalized', 'tx.itxJson.actualFee']));
|
|
883
|
-
|
|
884
|
-
module.exports = {
|
|
885
|
-
create,
|
|
886
|
-
update,
|
|
887
|
-
getTxReceiver,
|
|
888
|
-
getTxSender,
|
|
889
|
-
getTxReceipts,
|
|
890
|
-
mergeTxReceipts,
|
|
891
|
-
attachPaidTxGas,
|
|
892
|
-
verifyTxReceipts,
|
|
893
|
-
eachReceipts,
|
|
894
|
-
groupReceiptTokenChanges,
|
|
895
|
-
FORGE_TOKEN_HOLDER,
|
|
896
|
-
};
|