@ocap/tx-protocols 1.18.22 → 1.18.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/execute.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* eslint-disable consistent-return */
|
|
2
|
+
const { promisify } = require('util');
|
|
2
3
|
const get = require('lodash/get');
|
|
3
4
|
const pick = require('lodash/pick');
|
|
4
5
|
const omit = require('lodash/omit');
|
|
@@ -6,6 +7,12 @@ const camelCase = require('lodash/camelCase');
|
|
|
6
7
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
7
8
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
8
9
|
|
|
10
|
+
const createEnsureGasFn = require('./pipes/ensure-gas');
|
|
11
|
+
const createEnsureCostFn = require('./pipes/ensure-cost');
|
|
12
|
+
|
|
13
|
+
const ensureTxGas = promisify(createEnsureGasFn(() => ({ create: 0, update: 2 })));
|
|
14
|
+
const ensureTxCost = promisify(createEnsureCostFn({ attachSenderChanges: true, gasOnly: true }));
|
|
15
|
+
|
|
9
16
|
const getTxName = (typeUrl) => camelCase(typeUrl.split(':').pop());
|
|
10
17
|
|
|
11
18
|
const flushEvents = (context, extra = {}) => {
|
|
@@ -16,6 +23,7 @@ const flushEvents = (context, extra = {}) => {
|
|
|
16
23
|
};
|
|
17
24
|
|
|
18
25
|
const shouldPersistTx = (err) => !err || get(err, 'props.persist');
|
|
26
|
+
const logError = (...args) => process.env.NODE_ENV !== 'test' && console.error(...args);
|
|
19
27
|
|
|
20
28
|
module.exports = ({ filter, runAsLambda }) => {
|
|
21
29
|
// pipeline before executing the transaction
|
|
@@ -41,13 +49,33 @@ module.exports = ({ filter, runAsLambda }) => {
|
|
|
41
49
|
pre.use(pipes.VerifyTxSize);
|
|
42
50
|
pre.use(pipes.VerifySignature);
|
|
43
51
|
|
|
52
|
+
// charge gas fee for errored tx
|
|
53
|
+
const ensureGasFeePaid = async (context) => {
|
|
54
|
+
try {
|
|
55
|
+
await ensureTxGas(context);
|
|
56
|
+
await ensureTxCost(context);
|
|
57
|
+
|
|
58
|
+
const { tx, statedb, senderState, senderUpdates, updateVaults } = context;
|
|
59
|
+
|
|
60
|
+
await Promise.all([
|
|
61
|
+
statedb.account.update(
|
|
62
|
+
senderState.address,
|
|
63
|
+
context.states.account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
64
|
+
context
|
|
65
|
+
),
|
|
66
|
+
|
|
67
|
+
updateVaults(),
|
|
68
|
+
]);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
logError('Failed to charge gas fee for errored tx', err);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
44
74
|
const execute = async (context, protocols, isRetrySupported = false) =>
|
|
45
75
|
new Promise((resolve, reject) => {
|
|
46
76
|
pre.run(context, (err) => {
|
|
47
77
|
if (err) {
|
|
48
|
-
|
|
49
|
-
console.error('Failed to prepare transaction', err);
|
|
50
|
-
}
|
|
78
|
+
logError('Failed to prepare transaction', err);
|
|
51
79
|
return reject(err);
|
|
52
80
|
}
|
|
53
81
|
|
|
@@ -62,12 +90,16 @@ module.exports = ({ filter, runAsLambda }) => {
|
|
|
62
90
|
// we should only flush events when retry is not supported
|
|
63
91
|
// otherwise the outer caller should handle these 2
|
|
64
92
|
if (shouldPersistTx(err) && isRetrySupported === false) {
|
|
93
|
+
if (err) {
|
|
94
|
+
await ensureGasFeePaid(context);
|
|
95
|
+
}
|
|
96
|
+
|
|
65
97
|
let txState;
|
|
66
98
|
try {
|
|
67
99
|
txState = context.states.tx.create(context, err ? err.code || 'INTERNAL' : 'OK');
|
|
68
100
|
await context.statedb.tx.create(txState.hash, txState, context);
|
|
69
101
|
} catch (e) {
|
|
70
|
-
|
|
102
|
+
logError('Failed to save transaction to statedb', e);
|
|
71
103
|
return reject(e);
|
|
72
104
|
}
|
|
73
105
|
|
|
@@ -76,7 +108,7 @@ module.exports = ({ filter, runAsLambda }) => {
|
|
|
76
108
|
|
|
77
109
|
// after executing the transaction
|
|
78
110
|
if (err) {
|
|
79
|
-
|
|
111
|
+
logError('Failed to execute transaction', err);
|
|
80
112
|
return reject(err);
|
|
81
113
|
}
|
|
82
114
|
|
|
@@ -102,15 +134,20 @@ module.exports = ({ filter, runAsLambda }) => {
|
|
|
102
134
|
} finally {
|
|
103
135
|
if (shouldPersistTx(error)) {
|
|
104
136
|
try {
|
|
105
|
-
|
|
137
|
+
let txState = context.states.tx.create(ctx, error ? error.code || 'INTERNAL' : 'OK');
|
|
106
138
|
flushEvents(ctx, { txState });
|
|
107
139
|
await runAsLambda(async (txn) => {
|
|
108
140
|
const newCtx = { ...omit(ctx, ['txn']), txn };
|
|
141
|
+
if (error) {
|
|
142
|
+
await ensureGasFeePaid(newCtx);
|
|
143
|
+
// Recreate tx to pick up gas related fields
|
|
144
|
+
txState = context.states.tx.create(newCtx, error ? error.code || 'INTERNAL' : 'OK');
|
|
145
|
+
}
|
|
109
146
|
await context.statedb.tx.create(txState.hash, txState, newCtx);
|
|
110
147
|
flushEvents(newCtx, { txState });
|
|
111
148
|
});
|
|
112
149
|
} catch (err) {
|
|
113
|
-
|
|
150
|
+
logError('failed to save invalid transaction to statedb', err);
|
|
114
151
|
}
|
|
115
152
|
}
|
|
116
153
|
}
|
package/lib/pipes/ensure-cost.js
CHANGED
|
@@ -15,7 +15,7 @@ const { applyTokenUpdates, isGasStakeValid } = require('../util');
|
|
|
15
15
|
// - gas: charged for every tx for creating/updating states on the ledger
|
|
16
16
|
// - service fee: charged for creating tokens/assets/factories/rollups
|
|
17
17
|
// - protocol fee: charged for moving tokens across the bridge
|
|
18
|
-
module.exports = function CreateEnsureTxCostPipe({ attachSenderChanges = true } = {}) {
|
|
18
|
+
module.exports = function CreateEnsureTxCostPipe({ attachSenderChanges = true, gasOnly = false } = {}) {
|
|
19
19
|
return async function EnsureTxCost(context, next) {
|
|
20
20
|
// TODO: we are using the sender as gas payer, this may change in future
|
|
21
21
|
const { config, statedb, txType, senderState, gasEstimate, gasVaultState, totalGas } = context;
|
|
@@ -25,7 +25,7 @@ module.exports = function CreateEnsureTxCostPipe({ attachSenderChanges = true }
|
|
|
25
25
|
const changes = {};
|
|
26
26
|
let txCost = new BN(0);
|
|
27
27
|
const txFee = config.transaction.txFee[txType];
|
|
28
|
-
if (txFee) {
|
|
28
|
+
if (!gasOnly && txFee) {
|
|
29
29
|
const totalFee = fromTokenToUnit(txFee, config.token.decimal);
|
|
30
30
|
txCost = txCost.add(totalFee);
|
|
31
31
|
changes.fee = { address: config.token.address, value: totalFee.toString(10) };
|
|
@@ -145,6 +145,8 @@ module.exports = function CreateEnsureTxCostPipe({ attachSenderChanges = true }
|
|
|
145
145
|
});
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
context.gasPaid = true;
|
|
148
150
|
};
|
|
149
151
|
} else {
|
|
150
152
|
context.senderUpdates = {};
|
|
@@ -39,17 +39,18 @@ runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
|
39
39
|
// Ensure factory exist
|
|
40
40
|
runner.use(pipes.ExtractState({ from: 'itx.factory', to: 'factoryState', status: 'INVALID_FACTORY_STATE', table: 'factory' })); // prettier-ignore
|
|
41
41
|
|
|
42
|
-
//
|
|
43
|
-
runner.use(pipes.ExtractState({ from: 'factoryState.
|
|
42
|
+
// Ensure issuer exist: read them here because some maybe migrated
|
|
43
|
+
runner.use(pipes.ExtractState({ from: 'factoryState.trustedIssuers', to: 'issuerStates', status: 'INVALID_ISSUER_STATE' , table: 'account'})); // prettier-ignore
|
|
44
44
|
|
|
45
45
|
// Ensure factory owner exist and equal to sender
|
|
46
46
|
runner.use(pipes.ExtractState({ from: 'itx.owner', to: 'ownerState', status: 'OK', table: 'account' }));
|
|
47
47
|
runner.use(
|
|
48
48
|
pipes.VerifyInfo([
|
|
49
49
|
{
|
|
50
|
-
error: '
|
|
51
|
-
message: 'Only factory owner
|
|
52
|
-
fn: ({ factoryState, senderState }) =>
|
|
50
|
+
error: 'FORBIDDEN',
|
|
51
|
+
message: 'Only factory owner and trusted issuers are allowed to mint',
|
|
52
|
+
fn: ({ factoryState, senderState, issuerStates }) =>
|
|
53
|
+
senderState.address === factoryState.owner || issuerStates.find((x) => x.address === senderState.address),
|
|
53
54
|
persist: true,
|
|
54
55
|
},
|
|
55
56
|
])
|
|
@@ -2,7 +2,7 @@ const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
|
2
2
|
const { mintFromFactory } = require('@ocap/asset');
|
|
3
3
|
|
|
4
4
|
module.exports = (mode) => (context, next) => {
|
|
5
|
-
const { itx, senderState, ownerState, factoryState, delegatorState,
|
|
5
|
+
const { itx, senderState, ownerState, factoryState, delegatorState, factoryInputs } = context;
|
|
6
6
|
|
|
7
7
|
let issuer = null;
|
|
8
8
|
let owner = null;
|
|
@@ -17,9 +17,9 @@ module.exports = (mode) => (context, next) => {
|
|
|
17
17
|
} else if (mode === 'mint') {
|
|
18
18
|
owner = ownerState || { address: itx.owner };
|
|
19
19
|
issuer = {
|
|
20
|
-
id:
|
|
21
|
-
pk:
|
|
22
|
-
name:
|
|
20
|
+
id: senderState.address,
|
|
21
|
+
pk: senderState.pk,
|
|
22
|
+
name: senderState.moniker,
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -107,6 +107,9 @@ runner.use((context, next) => {
|
|
|
107
107
|
return next(new Error('INVALID_FACTORY_INPUT', 'Not all input.assets exist on chain'));
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
// ensure issuer exists
|
|
111
|
+
runner.use(pipes.ExtractState({ from: 'factoryProps.trustedIssuers', to: 'issuerStates', table: 'account', status: 'INVALID_ISSUER_STATE' })); // prettier-ignore
|
|
112
|
+
|
|
110
113
|
// Ensure tx fee and gas
|
|
111
114
|
runner.use(EnsureTxGas(() => ({ create: 1, update: 1, payment: 0 })));
|
|
112
115
|
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
@@ -79,20 +79,23 @@ runner.use(
|
|
|
79
79
|
])
|
|
80
80
|
);
|
|
81
81
|
|
|
82
|
-
// Ensure
|
|
83
|
-
runner.use(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
82
|
+
// Ensure uniqueness of token symbol
|
|
83
|
+
runner.use(
|
|
84
|
+
async function EnsureTokenSymbol(context, next) {
|
|
85
|
+
const { symbol } = context.config.token;
|
|
86
|
+
if (symbol.toLowerCase() === context.itx.symbol.toLowerCase()) {
|
|
87
|
+
return next(new Error('DUPLICATE_SYMBOL', `Token symbol can not be ${symbol}`));
|
|
88
|
+
}
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
const exist = await context.statedb.token.existBySymbol(context.itx.symbol, context);
|
|
91
|
+
if (exist) {
|
|
92
|
+
return next(new Error('DUPLICATE_SYMBOL', 'Token symbol already exists'));
|
|
93
|
+
}
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
}
|
|
95
|
+
return next();
|
|
96
|
+
},
|
|
97
|
+
{ persistError: true }
|
|
98
|
+
);
|
|
96
99
|
|
|
97
100
|
// Ensure tx fee and gas
|
|
98
101
|
runner.use(
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.18.
|
|
6
|
+
"version": "1.18.24",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@arcblock/did": "1.18.
|
|
25
|
-
"@arcblock/did-util": "1.18.
|
|
26
|
-
"@arcblock/jwt": "1.18.
|
|
27
|
-
"@arcblock/validator": "1.18.
|
|
28
|
-
"@ocap/asset": "1.18.
|
|
29
|
-
"@ocap/mcrypto": "1.18.
|
|
30
|
-
"@ocap/merkle-tree": "1.18.
|
|
31
|
-
"@ocap/message": "1.18.
|
|
32
|
-
"@ocap/state": "1.18.
|
|
33
|
-
"@ocap/tx-pipeline": "1.18.
|
|
34
|
-
"@ocap/util": "1.18.
|
|
35
|
-
"@ocap/wallet": "1.18.
|
|
24
|
+
"@arcblock/did": "1.18.24",
|
|
25
|
+
"@arcblock/did-util": "1.18.24",
|
|
26
|
+
"@arcblock/jwt": "1.18.24",
|
|
27
|
+
"@arcblock/validator": "1.18.24",
|
|
28
|
+
"@ocap/asset": "1.18.24",
|
|
29
|
+
"@ocap/mcrypto": "1.18.24",
|
|
30
|
+
"@ocap/merkle-tree": "1.18.24",
|
|
31
|
+
"@ocap/message": "1.18.24",
|
|
32
|
+
"@ocap/state": "1.18.24",
|
|
33
|
+
"@ocap/tx-pipeline": "1.18.24",
|
|
34
|
+
"@ocap/util": "1.18.24",
|
|
35
|
+
"@ocap/wallet": "1.18.24",
|
|
36
36
|
"debug": "^4.3.4",
|
|
37
37
|
"deep-diff": "^1.0.2",
|
|
38
38
|
"empty-value": "^1.0.1",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"jest": "^27.5.1",
|
|
48
48
|
"start-server-and-test": "^1.14.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "2b3c7ab2de31bd3ef55ae32cec5c007d5e13d306"
|
|
51
51
|
}
|