@ocap/tx-protocols 1.17.22 → 1.18.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/lib/pipes/ensure-cost.js +116 -0
- package/lib/pipes/ensure-gas.js +53 -0
- package/lib/protocols/account/delegate.js +30 -3
- package/lib/protocols/account/migrate.js +15 -1
- package/lib/protocols/account/revoke-delegate.js +14 -2
- package/lib/protocols/asset/acquire-v2.js +25 -2
- package/lib/protocols/asset/acquire-v3.js +34 -2
- package/lib/protocols/asset/create.js +9 -10
- package/lib/protocols/asset/mint.js +28 -2
- package/lib/protocols/asset/pipes/exec-mint-hook.js +1 -1
- package/lib/protocols/asset/update.js +11 -2
- package/lib/protocols/factory/create.js +8 -9
- package/lib/protocols/governance/claim-stake.js +41 -4
- package/lib/protocols/governance/revoke-stake.js +14 -3
- package/lib/protocols/governance/stake.js +53 -4
- package/lib/protocols/rollup/claim-reward.js +46 -16
- package/lib/protocols/rollup/create-block.js +35 -3
- package/lib/protocols/rollup/create.js +8 -18
- package/lib/protocols/rollup/join.js +25 -2
- package/lib/protocols/rollup/leave.js +15 -2
- package/lib/protocols/rollup/migrate-contract.js +13 -2
- package/lib/protocols/rollup/migrate-token.js +13 -2
- package/lib/protocols/rollup/pause.js +13 -2
- package/lib/protocols/rollup/resume.js +13 -2
- package/lib/protocols/rollup/update.js +13 -2
- package/lib/protocols/token/create.js +19 -9
- package/lib/protocols/token/deposit-v2.js +46 -6
- package/lib/protocols/token/withdraw-v2.js +43 -6
- package/lib/protocols/trade/exchange-v2.js +36 -3
- package/lib/protocols/trade/transfer-v2.js +27 -2
- package/lib/protocols/trade/transfer-v3.js +34 -1
- package/lib/util.js +7 -7
- package/package.json +13 -13
- package/lib/protocols/rollup/pipes/ensure-service-fee.js +0 -37
|
@@ -5,6 +5,8 @@ const { account, rollup } = require('@ocap/state');
|
|
|
5
5
|
|
|
6
6
|
const VerifySigners = require('./pipes/verify-signers');
|
|
7
7
|
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
9
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
8
10
|
|
|
9
11
|
const runner = new Runner();
|
|
10
12
|
|
|
@@ -31,14 +33,23 @@ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INV
|
|
|
31
33
|
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
32
34
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
33
35
|
|
|
36
|
+
// Ensure tx fee and gas
|
|
37
|
+
runner.use(EnsureTxGas(() => ({ create: 0, update: 2, payment: 0 })));
|
|
38
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
39
|
+
|
|
34
40
|
// 5. update rollup state
|
|
35
41
|
runner.use(
|
|
36
42
|
async (context, next) => {
|
|
37
|
-
const { tx, itx, rollupState, statedb, senderState } = context;
|
|
43
|
+
const { tx, itx, rollupState, statedb, senderState, senderUpdates, updateVaults } = context;
|
|
38
44
|
|
|
39
45
|
const [newSenderState, newRollupState] = await Promise.all([
|
|
40
|
-
statedb.account.update(
|
|
46
|
+
statedb.account.update(
|
|
47
|
+
senderState.address,
|
|
48
|
+
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
49
|
+
context
|
|
50
|
+
),
|
|
41
51
|
statedb.rollup.update(itx.rollup, rollup.pause(rollupState, context), context),
|
|
52
|
+
updateVaults(),
|
|
42
53
|
]);
|
|
43
54
|
|
|
44
55
|
context.senderState = newSenderState;
|
|
@@ -5,6 +5,8 @@ const { account, rollup } = require('@ocap/state');
|
|
|
5
5
|
|
|
6
6
|
const VerifySigners = require('./pipes/verify-signers');
|
|
7
7
|
const EnsureValidator = require('./pipes/ensure-validator');
|
|
8
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
9
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
8
10
|
|
|
9
11
|
const runner = new Runner();
|
|
10
12
|
|
|
@@ -31,14 +33,23 @@ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INV
|
|
|
31
33
|
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
32
34
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
33
35
|
|
|
36
|
+
// Ensure tx fee and gas
|
|
37
|
+
runner.use(EnsureTxGas(() => ({ create: 0, update: 2, payment: 0 })));
|
|
38
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
39
|
+
|
|
34
40
|
// 5. update rollup state
|
|
35
41
|
runner.use(
|
|
36
42
|
async (context, next) => {
|
|
37
|
-
const { tx, itx, rollupState, statedb, senderState } = context;
|
|
43
|
+
const { tx, itx, rollupState, statedb, senderState, senderUpdates, updateVaults } = context;
|
|
38
44
|
|
|
39
45
|
const [newSenderState, newRollupState] = await Promise.all([
|
|
40
|
-
statedb.account.update(
|
|
46
|
+
statedb.account.update(
|
|
47
|
+
senderState.address,
|
|
48
|
+
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
49
|
+
context
|
|
50
|
+
),
|
|
41
51
|
statedb.rollup.update(itx.rollup, rollup.resume(rollupState, context), context),
|
|
52
|
+
updateVaults(),
|
|
42
53
|
]);
|
|
43
54
|
|
|
44
55
|
context.senderState = newSenderState;
|
|
@@ -7,6 +7,8 @@ const { account, rollup } = require('@ocap/state');
|
|
|
7
7
|
const debug = require('debug')(`${require('../../../package.json').name}:update-rollup`);
|
|
8
8
|
|
|
9
9
|
const VerifySigners = require('./pipes/verify-signers');
|
|
10
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
11
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
10
12
|
|
|
11
13
|
const { decodeAnySafe } = require('../../util');
|
|
12
14
|
|
|
@@ -74,15 +76,24 @@ runner.use(
|
|
|
74
76
|
);
|
|
75
77
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
76
78
|
|
|
79
|
+
// Ensure tx fee and gas
|
|
80
|
+
runner.use(EnsureTxGas(() => ({ create: 0, update: 2, payment: 0 })));
|
|
81
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
82
|
+
|
|
77
83
|
// 5. update rollup state
|
|
78
84
|
runner.use(
|
|
79
85
|
async (context, next) => {
|
|
80
|
-
const { tx, itx, rollupState, statedb, senderState } = context;
|
|
86
|
+
const { tx, itx, rollupState, statedb, senderState, senderUpdates, updateVaults } = context;
|
|
81
87
|
const data = decodeAnySafe(itx.data);
|
|
82
88
|
|
|
83
89
|
const [newSenderState, newRollupState] = await Promise.all([
|
|
84
|
-
statedb.account.update(
|
|
90
|
+
statedb.account.update(
|
|
91
|
+
senderState.address,
|
|
92
|
+
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
93
|
+
context
|
|
94
|
+
),
|
|
85
95
|
statedb.rollup.update(itx.rollup, rollup.update(rollupState, { ...itx, data }, context), context),
|
|
96
|
+
updateVaults(),
|
|
86
97
|
]);
|
|
87
98
|
|
|
88
99
|
context.senderState = newSenderState;
|
|
@@ -10,7 +10,9 @@ const { fromTokenToUnit } = require('@ocap/util');
|
|
|
10
10
|
// eslint-disable-next-line global-require
|
|
11
11
|
const debug = require('debug')(`${require('../../../package.json').name}:create-token`);
|
|
12
12
|
const { decodeAnySafe } = require('../../util');
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
15
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
14
16
|
|
|
15
17
|
const MAX_TOTAL_SUPPLY = fromTokenToUnit(10000 * 100000000, 18); // 32
|
|
16
18
|
|
|
@@ -92,12 +94,23 @@ runner.use(async (context, next) => {
|
|
|
92
94
|
return next();
|
|
93
95
|
});
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
// Ensure tx fee and gas
|
|
98
|
+
runner.use(
|
|
99
|
+
EnsureTxGas((context) => {
|
|
100
|
+
const result = { create: 1, update: 1, payment: 0 };
|
|
101
|
+
if (context.delegatorState) {
|
|
102
|
+
result.update += 1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
96
109
|
|
|
97
110
|
// Update sender state, token state
|
|
98
111
|
runner.use(
|
|
99
112
|
async (context, next) => {
|
|
100
|
-
const { tx, itx, statedb, senderState, delegatorState, senderUpdates,
|
|
113
|
+
const { tx, itx, statedb, senderState, delegatorState, senderUpdates, updateVaults } = context;
|
|
101
114
|
const data = decodeAnySafe(itx.data);
|
|
102
115
|
const owner = delegatorState ? delegatorState.address : senderState.address;
|
|
103
116
|
|
|
@@ -113,7 +126,7 @@ runner.use(
|
|
|
113
126
|
senderUpdates.tokens[itx.address] = itx.initialSupply;
|
|
114
127
|
}
|
|
115
128
|
|
|
116
|
-
const [newSenderState, tokenState,
|
|
129
|
+
const [newSenderState, tokenState, newDelegatorState] = await Promise.all([
|
|
117
130
|
statedb.account.update(
|
|
118
131
|
senderState.address,
|
|
119
132
|
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
@@ -122,10 +135,6 @@ runner.use(
|
|
|
122
135
|
|
|
123
136
|
statedb.token.create(itx.address, token.create({ ...cloneDeep(itx), data, issuer: owner }, context), context),
|
|
124
137
|
|
|
125
|
-
isEmpty(vaultUpdates)
|
|
126
|
-
? vaultState
|
|
127
|
-
: statedb.account.update(vaultState.address, account.update(vaultState, vaultUpdates, context), context),
|
|
128
|
-
|
|
129
138
|
delegatorState
|
|
130
139
|
? statedb.account.update(
|
|
131
140
|
delegatorState.address,
|
|
@@ -133,11 +142,12 @@ runner.use(
|
|
|
133
142
|
context
|
|
134
143
|
)
|
|
135
144
|
: null,
|
|
145
|
+
|
|
146
|
+
updateVaults(),
|
|
136
147
|
]);
|
|
137
148
|
|
|
138
149
|
context.senderState = newSenderState;
|
|
139
150
|
context.tokenState = tokenState;
|
|
140
|
-
context.vaultState = newVaultState;
|
|
141
151
|
context.delegatorState = newDelegatorState;
|
|
142
152
|
|
|
143
153
|
debug('create token v2', tokenState);
|
|
@@ -10,9 +10,12 @@ const { toStakeAddress } = require('@arcblock/did-util');
|
|
|
10
10
|
// eslint-disable-next-line global-require
|
|
11
11
|
const debug = require('debug')(`${require('../../../package.json').name}:deposit-token`);
|
|
12
12
|
|
|
13
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
14
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
15
|
+
|
|
13
16
|
const VerifySigners = require('../rollup/pipes/verify-signers');
|
|
14
17
|
const VerifyPaused = require('../rollup/pipes/verify-paused');
|
|
15
|
-
const { applyTokenUpdates, getTxFee, getBNSum, getRewardLocker } = require('../../util');
|
|
18
|
+
const { applyTokenUpdates, applyTokenChange, getTxFee, getBNSum, getRewardLocker } = require('../../util');
|
|
16
19
|
|
|
17
20
|
const schema = Joi.object({
|
|
18
21
|
token: schemas.tokenInput.required(),
|
|
@@ -160,23 +163,58 @@ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK'
|
|
|
160
163
|
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
161
164
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
162
165
|
|
|
166
|
+
// Ensure tx fee and gas
|
|
167
|
+
runner.use(
|
|
168
|
+
EnsureTxGas((context) => {
|
|
169
|
+
// FIXME: payment check
|
|
170
|
+
const result = { create: 1, update: 1, payment: 0 };
|
|
171
|
+
if (context.senderState) {
|
|
172
|
+
result.update += 1;
|
|
173
|
+
} else {
|
|
174
|
+
result.create += 1;
|
|
175
|
+
}
|
|
176
|
+
if (context.lockerState) {
|
|
177
|
+
result.update += 1;
|
|
178
|
+
} else {
|
|
179
|
+
result.create += 1;
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
})
|
|
183
|
+
);
|
|
184
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
185
|
+
|
|
163
186
|
// 8. update state: the token minting is done when deposit finalized in rollup-block
|
|
164
187
|
runner.use(
|
|
165
188
|
async (context, next) => {
|
|
166
|
-
const {
|
|
189
|
+
const {
|
|
190
|
+
tx,
|
|
191
|
+
itx,
|
|
192
|
+
statedb,
|
|
193
|
+
senderState,
|
|
194
|
+
stakeState,
|
|
195
|
+
stakeAddress,
|
|
196
|
+
lockerState,
|
|
197
|
+
lockerAddress,
|
|
198
|
+
senderChange,
|
|
199
|
+
updateVaults,
|
|
200
|
+
} = context;
|
|
167
201
|
|
|
168
202
|
const user = itx.token.value;
|
|
169
203
|
const fee = itx.actualFee;
|
|
170
204
|
const total = getBNSum(user, fee);
|
|
171
205
|
|
|
172
206
|
const stakeUpdates = applyTokenUpdates([{ address: itx.token.address, value: total }], stakeState, 'sub');
|
|
173
|
-
|
|
207
|
+
let senderUpdates = applyTokenUpdates([{ address: itx.token.address, value: user }], senderState || {}, 'add');
|
|
174
208
|
const lockerUpdates = applyTokenUpdates(
|
|
175
209
|
[{ address: itx.token.address, value: fee }],
|
|
176
210
|
lockerState || { tokens: {} },
|
|
177
211
|
'add'
|
|
178
212
|
);
|
|
179
213
|
|
|
214
|
+
if (senderChange && senderState) {
|
|
215
|
+
senderUpdates = applyTokenChange(senderUpdates, senderChange);
|
|
216
|
+
}
|
|
217
|
+
|
|
180
218
|
const sender = senderState ? senderState.address : tx.from;
|
|
181
219
|
const [newSenderState, newStakeState, newLockerState, evidenceState] = await Promise.all([
|
|
182
220
|
// updateOrCreate user account
|
|
@@ -215,6 +253,8 @@ runner.use(
|
|
|
215
253
|
evidence.create({ hash: itx.evidence.hash, data: 'rollup-deposit' }, context),
|
|
216
254
|
context
|
|
217
255
|
),
|
|
256
|
+
|
|
257
|
+
updateVaults(),
|
|
218
258
|
]);
|
|
219
259
|
|
|
220
260
|
context.senderState = newSenderState;
|
|
@@ -222,14 +262,14 @@ runner.use(
|
|
|
222
262
|
context.evidenceState = evidenceState;
|
|
223
263
|
context.stakeStates = [newStakeState, newLockerState];
|
|
224
264
|
|
|
225
|
-
context.updatedAccounts
|
|
265
|
+
context.updatedAccounts.push(
|
|
226
266
|
// stake for tx proposer is decreased
|
|
227
267
|
{ address: stakeAddress, token: itx.token.address, delta: `-${total}`, action: 'unlock' },
|
|
228
268
|
// mint to depositor from stake
|
|
229
269
|
{ address: sender, token: itx.token.address, delta: user, action: 'unlock' },
|
|
230
270
|
// tx fee is locked for later claiming
|
|
231
|
-
{ address: lockerAddress, token: itx.token.address, delta: fee, action: 'pending' }
|
|
232
|
-
|
|
271
|
+
{ address: lockerAddress, token: itx.token.address, delta: fee, action: 'pending' }
|
|
272
|
+
);
|
|
233
273
|
|
|
234
274
|
debug('deposit-token-v2', itx);
|
|
235
275
|
|
|
@@ -10,8 +10,11 @@ const { toStakeAddress } = require('@arcblock/did-util');
|
|
|
10
10
|
// eslint-disable-next-line global-require
|
|
11
11
|
const debug = require('debug')(`${require('../../../package.json').name}:withdraw-token`);
|
|
12
12
|
|
|
13
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
14
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
15
|
+
|
|
13
16
|
const VerifyPaused = require('../rollup/pipes/verify-paused');
|
|
14
|
-
const { applyTokenUpdates, getTxFee, getBNSum, getRewardLocker } = require('../../util');
|
|
17
|
+
const { applyTokenUpdates, getTxFee, getBNSum, getRewardLocker, applyTokenChange } = require('../../util');
|
|
15
18
|
|
|
16
19
|
const verifyMultiSigV2 = pipes.VerifyMultiSigV2({ signersKey: 'signers' });
|
|
17
20
|
|
|
@@ -161,15 +164,47 @@ runner.use((context, next) => {
|
|
|
161
164
|
return next();
|
|
162
165
|
});
|
|
163
166
|
|
|
167
|
+
// Ensure tx fee and gas
|
|
168
|
+
runner.use(
|
|
169
|
+
EnsureTxGas((context) => {
|
|
170
|
+
// FIXME: payment check
|
|
171
|
+
const result = { create: 0, update: 1, payment: 0 };
|
|
172
|
+
if (context.stakeState) {
|
|
173
|
+
result.update += 1;
|
|
174
|
+
} else {
|
|
175
|
+
result.create += 1;
|
|
176
|
+
}
|
|
177
|
+
if (context.lockerState) {
|
|
178
|
+
result.update += 1;
|
|
179
|
+
} else {
|
|
180
|
+
result.create += 1;
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
186
|
+
|
|
164
187
|
// 8. update state: the fee splitting and token burning is done when withdraw finalized in rollup-block
|
|
165
188
|
runner.use(
|
|
166
189
|
async (context, next) => {
|
|
167
|
-
const {
|
|
190
|
+
const {
|
|
191
|
+
tx,
|
|
192
|
+
itx,
|
|
193
|
+
statedb,
|
|
194
|
+
stakeState,
|
|
195
|
+
senderState,
|
|
196
|
+
lockerState,
|
|
197
|
+
lockerAddress,
|
|
198
|
+
stakeAddress,
|
|
199
|
+
senderChange,
|
|
200
|
+
updateVaults,
|
|
201
|
+
} = context;
|
|
168
202
|
|
|
169
203
|
const total = getBNSum(itx.token.value, itx.actualFee, itx.maxFee);
|
|
170
204
|
const fee = getBNSum(itx.actualFee, itx.maxFee);
|
|
171
205
|
|
|
172
|
-
|
|
206
|
+
let senderUpdates = applyTokenUpdates([{ address: itx.token.address, value: total }], senderState, 'sub');
|
|
207
|
+
senderUpdates = applyTokenChange(senderUpdates, senderChange);
|
|
173
208
|
|
|
174
209
|
// Burned amount should equal to user received amount
|
|
175
210
|
const stakeUpdates = applyTokenUpdates(
|
|
@@ -232,6 +267,8 @@ runner.use(
|
|
|
232
267
|
),
|
|
233
268
|
context
|
|
234
269
|
),
|
|
270
|
+
|
|
271
|
+
updateVaults(),
|
|
235
272
|
]);
|
|
236
273
|
|
|
237
274
|
context.senderState = newSenderState;
|
|
@@ -239,11 +276,11 @@ runner.use(
|
|
|
239
276
|
context.lockerState = newLockerState;
|
|
240
277
|
context.stakeStates = [newStakeState, newLockerState];
|
|
241
278
|
|
|
242
|
-
context.updatedAccounts
|
|
279
|
+
context.updatedAccounts.push(
|
|
243
280
|
{ address: senderState.address, token: itx.token.address, delta: `-${total}`, action: 'lock' },
|
|
244
281
|
{ address: stakeAddress, token: itx.token.address, delta: itx.token.value, action: 'lock' },
|
|
245
|
-
{ address: lockerAddress, token: itx.token.address, delta: fee, action: 'pending' }
|
|
246
|
-
|
|
282
|
+
{ address: lockerAddress, token: itx.token.address, delta: fee, action: 'pending' }
|
|
283
|
+
);
|
|
247
284
|
|
|
248
285
|
debug('withdraw-token-v2', itx);
|
|
249
286
|
|
|
@@ -9,6 +9,10 @@ const { account } = require('@ocap/state');
|
|
|
9
9
|
// eslint-disable-next-line global-require
|
|
10
10
|
const debug = require('debug')(`${require('../../../package.json').name}:exchange-v2`);
|
|
11
11
|
|
|
12
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
13
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
14
|
+
const { applyTokenChange } = require('../../util');
|
|
15
|
+
|
|
12
16
|
const runner = new Runner();
|
|
13
17
|
|
|
14
18
|
runner.use(pipes.VerifyMultiSig(1));
|
|
@@ -122,13 +126,38 @@ runner.use(pipes.ExtractState({ from: 'receiverAssets', to: 'priv.receiverAssets
|
|
|
122
126
|
runner.use(pipes.VerifyTransferrable({ assets: 'priv.receiverAssets' }));
|
|
123
127
|
runner.use(pipes.VerifyUpdater({ assetKey: 'priv.receiverAssets', ownerKey: 'receiverState' }));
|
|
124
128
|
|
|
129
|
+
// Ensure tx fee and gas
|
|
130
|
+
runner.use(
|
|
131
|
+
EnsureTxGas((context) => {
|
|
132
|
+
// FIXME: payment check
|
|
133
|
+
const ops = { create: 0, update: 2, payment: 0 };
|
|
134
|
+
ops.update += context.senderAssets.length;
|
|
135
|
+
ops.update += context.receiverAssets.length;
|
|
136
|
+
|
|
137
|
+
return ops;
|
|
138
|
+
})
|
|
139
|
+
);
|
|
140
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
141
|
+
|
|
125
142
|
runner.use(pipes.UpdateOwner({ assets: 'priv.senderAssets', owner: 'receiverState' }));
|
|
126
143
|
runner.use(pipes.UpdateOwner({ assets: 'priv.receiverAssets', owner: 'senderState' }));
|
|
127
144
|
|
|
145
|
+
// update statedb
|
|
128
146
|
runner.use(
|
|
129
147
|
async (context, next) => {
|
|
130
|
-
const {
|
|
131
|
-
|
|
148
|
+
const {
|
|
149
|
+
tx,
|
|
150
|
+
itx,
|
|
151
|
+
senderAssets,
|
|
152
|
+
receiverAssets,
|
|
153
|
+
senderTokens,
|
|
154
|
+
receiverTokens,
|
|
155
|
+
senderState,
|
|
156
|
+
receiverState,
|
|
157
|
+
senderChange,
|
|
158
|
+
updateVaults,
|
|
159
|
+
statedb,
|
|
160
|
+
} = context;
|
|
132
161
|
|
|
133
162
|
const senderStateTokens = senderState.tokens || {};
|
|
134
163
|
const receiverStateTokens = receiverState.tokens || {};
|
|
@@ -145,11 +174,13 @@ runner.use(
|
|
|
145
174
|
receiverStateTokens[address] = new BN(receiverStateTokens[address] || '0').sub(delta).toString();
|
|
146
175
|
}
|
|
147
176
|
|
|
177
|
+
const senderUpdates = applyTokenChange({ tokens: senderStateTokens }, senderChange);
|
|
178
|
+
|
|
148
179
|
const [newSenderState, newReceiverState] = await Promise.all([
|
|
149
180
|
// Update sender state
|
|
150
181
|
statedb.account.update(
|
|
151
182
|
senderState.address,
|
|
152
|
-
account.update(senderState, { nonce: tx.nonce,
|
|
183
|
+
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
153
184
|
context
|
|
154
185
|
),
|
|
155
186
|
|
|
@@ -159,6 +190,8 @@ runner.use(
|
|
|
159
190
|
account.update(receiverState, { tokens: receiverStateTokens }, context),
|
|
160
191
|
context
|
|
161
192
|
),
|
|
193
|
+
|
|
194
|
+
updateVaults(),
|
|
162
195
|
]);
|
|
163
196
|
|
|
164
197
|
context.senderState = newSenderState;
|
|
@@ -8,6 +8,10 @@ const { account } = require('@ocap/state');
|
|
|
8
8
|
// eslint-disable-next-line global-require
|
|
9
9
|
const debug = require('debug')(`${require('../../../package.json').name}:transfer-v2`);
|
|
10
10
|
|
|
11
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
12
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
13
|
+
const { applyTokenChange } = require('../../util');
|
|
14
|
+
|
|
11
15
|
const runner = new Runner();
|
|
12
16
|
|
|
13
17
|
runner.use(pipes.VerifyMultiSig(0));
|
|
@@ -86,6 +90,23 @@ runner.use(pipes.ExtractState({ from: 'assets', to: 'assetStates', status: 'INVA
|
|
|
86
90
|
runner.use(pipes.VerifyTransferrable({ assets: 'assetStates' }));
|
|
87
91
|
runner.use(pipes.VerifyUpdater({ assetKey: 'assetStates', ownerKey: 'senderState' }));
|
|
88
92
|
|
|
93
|
+
// Ensure tx fee and gas
|
|
94
|
+
runner.use(
|
|
95
|
+
EnsureTxGas((context) => {
|
|
96
|
+
// FIXME: payment check
|
|
97
|
+
const result = { create: 0, update: 1, payment: 0 };
|
|
98
|
+
|
|
99
|
+
if (context.receiverState) {
|
|
100
|
+
result.update += 1;
|
|
101
|
+
} else {
|
|
102
|
+
result.create += 1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result;
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
109
|
+
|
|
89
110
|
// transfer assets to new owner
|
|
90
111
|
runner.use((context, next) => {
|
|
91
112
|
const { itx, receiverState } = context;
|
|
@@ -97,7 +118,7 @@ runner.use(pipes.UpdateOwner({ assets: 'assetStates', owner: 'receiverAddr' }));
|
|
|
97
118
|
// update statedb: transfer tokens to new owner
|
|
98
119
|
runner.use(
|
|
99
120
|
async (context, next) => {
|
|
100
|
-
const { tx, itx, tokens, senderState, receiverAddr, receiverState, statedb } = context;
|
|
121
|
+
const { tx, itx, tokens, senderState, receiverAddr, receiverState, statedb, senderChange, updateVaults } = context;
|
|
101
122
|
|
|
102
123
|
const { tokens: senderTokens = {} } = senderState;
|
|
103
124
|
const { tokens: receiverTokens = {} } = receiverState || {};
|
|
@@ -107,11 +128,13 @@ runner.use(
|
|
|
107
128
|
receiverTokens[token.address] = new BN(receiverTokens[token.address] || '0').add(delta).toString();
|
|
108
129
|
}
|
|
109
130
|
|
|
131
|
+
const senderUpdates = applyTokenChange({ tokens: senderTokens }, senderChange);
|
|
132
|
+
|
|
110
133
|
const [newSenderState, newReceiverState] = await Promise.all([
|
|
111
134
|
// Update sender state
|
|
112
135
|
statedb.account.update(
|
|
113
136
|
senderState.address,
|
|
114
|
-
account.update(senderState, { nonce: tx.nonce, pk: tx.pk,
|
|
137
|
+
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
115
138
|
context
|
|
116
139
|
),
|
|
117
140
|
|
|
@@ -121,6 +144,8 @@ runner.use(
|
|
|
121
144
|
account.updateOrCreate(receiverState, { address: receiverAddr, tokens: receiverTokens }, context),
|
|
122
145
|
context
|
|
123
146
|
),
|
|
147
|
+
|
|
148
|
+
updateVaults(),
|
|
124
149
|
]);
|
|
125
150
|
|
|
126
151
|
context.senderState = newSenderState;
|
|
@@ -11,7 +11,9 @@ const { getRelatedAddresses } = require('@ocap/util/lib/get-related-addr');
|
|
|
11
11
|
// eslint-disable-next-line global-require
|
|
12
12
|
const debug = require('debug')(`${require('../../../package.json').name}:transfer-v2`);
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
15
|
+
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
16
|
+
const { applyTokenUpdates, applyTokenChange } = require('../../util');
|
|
15
17
|
|
|
16
18
|
const runner = new Runner();
|
|
17
19
|
|
|
@@ -139,6 +141,27 @@ runner.use(async (context, next) => {
|
|
|
139
141
|
return next();
|
|
140
142
|
});
|
|
141
143
|
|
|
144
|
+
// Ensure tx fee and gas
|
|
145
|
+
runner.use(
|
|
146
|
+
EnsureTxGas((context) => {
|
|
147
|
+
// FIXME: payment check
|
|
148
|
+
const ops = { create: 0, update: 0, payment: 0 };
|
|
149
|
+
ops.update += context.signerStates.length;
|
|
150
|
+
ops.update += context.inputAssets.length;
|
|
151
|
+
ops.update += context.receivers.length;
|
|
152
|
+
|
|
153
|
+
if (context.senderState) {
|
|
154
|
+
ops.update += 1;
|
|
155
|
+
} else {
|
|
156
|
+
ops.create += 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return ops;
|
|
160
|
+
})
|
|
161
|
+
);
|
|
162
|
+
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
163
|
+
|
|
164
|
+
// Update statedb
|
|
142
165
|
runner.use(
|
|
143
166
|
async (context, next) => {
|
|
144
167
|
const {
|
|
@@ -148,6 +171,8 @@ runner.use(
|
|
|
148
171
|
receivers,
|
|
149
172
|
senderState,
|
|
150
173
|
signerStates,
|
|
174
|
+
senderChange,
|
|
175
|
+
updateVaults,
|
|
151
176
|
receiverStates = [],
|
|
152
177
|
assetStates = [],
|
|
153
178
|
statedb,
|
|
@@ -161,6 +186,9 @@ runner.use(
|
|
|
161
186
|
signerStates.find((s) => s.address === owner),
|
|
162
187
|
'sub'
|
|
163
188
|
);
|
|
189
|
+
if (senderChange && owner === senderChange.address) {
|
|
190
|
+
signerUpdates[owner] = applyTokenChange(signerUpdates[owner], senderChange);
|
|
191
|
+
}
|
|
164
192
|
});
|
|
165
193
|
|
|
166
194
|
const receiverUpdates = {};
|
|
@@ -169,6 +197,9 @@ runner.use(
|
|
|
169
197
|
const { owner, tokensList, assetsList } = x;
|
|
170
198
|
const ownerState = receiverStates.find((s) => getRelatedAddresses(s).includes(owner)) || { address: owner };
|
|
171
199
|
receiverUpdates[ownerState.address] = applyTokenUpdates(tokensList, ownerState, 'add');
|
|
200
|
+
if (senderChange && ownerState.address === senderChange.address) {
|
|
201
|
+
receiverUpdates[ownerState.address] = applyTokenChange(receiverUpdates[ownerState.address], senderChange);
|
|
202
|
+
}
|
|
172
203
|
assetsList.forEach((address) => {
|
|
173
204
|
assetUpdates[address] = { owner: ownerState.address };
|
|
174
205
|
});
|
|
@@ -224,6 +255,8 @@ runner.use(
|
|
|
224
255
|
statedb.asset.update(x.address, asset.update(x, assetUpdates[x.address], context), context)
|
|
225
256
|
)
|
|
226
257
|
),
|
|
258
|
+
|
|
259
|
+
updateVaults(),
|
|
227
260
|
]);
|
|
228
261
|
|
|
229
262
|
context.senderState = newSenderState;
|
package/lib/util.js
CHANGED
|
@@ -68,7 +68,7 @@ const applyTokenUpdates = (tokens, state, operator) => {
|
|
|
68
68
|
const requirement = new BN(value);
|
|
69
69
|
const balance = new BN(oldTokens[address] || 0);
|
|
70
70
|
const newBalance = balance[operator](requirement);
|
|
71
|
-
if (newBalance.
|
|
71
|
+
if (newBalance.isNeg()) {
|
|
72
72
|
throw new Error('NEGATIVE_TOKEN_BALANCE', `Negative token balance when applyTokenUpdates for ${address}`);
|
|
73
73
|
}
|
|
74
74
|
newTokens[address] = newBalance.toString(10);
|
|
@@ -104,13 +104,13 @@ const getTxFee = ({ amount, feeRate, maxFee, minFee, stringify = true }) => {
|
|
|
104
104
|
if (feeRate < 0) {
|
|
105
105
|
throw new Error('NEGATIVE_FEE_RATE', 'Unexpected negative feeRate when getTxFee, abort!');
|
|
106
106
|
}
|
|
107
|
-
if (userAmount.
|
|
107
|
+
if (userAmount.isNeg()) {
|
|
108
108
|
throw new Error('NEGATIVE_AMOUNT', 'Unexpected negative amount when getTxFee, abort!');
|
|
109
109
|
}
|
|
110
|
-
if (maxFeeAmount.
|
|
110
|
+
if (maxFeeAmount.isNeg()) {
|
|
111
111
|
throw new Error('NEGATIVE_MAX_FEE', 'Unexpected negative maxFee when getTxFee, abort!');
|
|
112
112
|
}
|
|
113
|
-
if (minFeeAmount.
|
|
113
|
+
if (minFeeAmount.isNeg()) {
|
|
114
114
|
throw new Error('NEGATIVE_MIN_FEE', 'Unexpected negative minFee when getTxFee, abort!');
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -143,7 +143,7 @@ const getTxFee = ({ amount, feeRate, maxFee, minFee, stringify = true }) => {
|
|
|
143
143
|
|
|
144
144
|
const splitTxFee = ({ total, shares = {}, stringify = true }) => {
|
|
145
145
|
const totalAmount = new BN(total);
|
|
146
|
-
if (totalAmount.
|
|
146
|
+
if (totalAmount.isNeg()) {
|
|
147
147
|
throw new Error('NEGATIVE_TOTAL_AMOUNT', 'Unexpected negative total when splitTxFee, abort!');
|
|
148
148
|
}
|
|
149
149
|
Object.keys(shares).forEach((key) => {
|
|
@@ -211,14 +211,14 @@ const ensureBlockReward = (rollupState, minReward, txStates) => {
|
|
|
211
211
|
|
|
212
212
|
let actualFee = new BN(0);
|
|
213
213
|
// If totalMissingFee is less than 0, then the tx will be charged for fixedFee
|
|
214
|
-
if (totalMissingFee.
|
|
214
|
+
if (totalMissingFee.isNeg()) {
|
|
215
215
|
actualFee = defaults.reward;
|
|
216
216
|
} else {
|
|
217
217
|
// Else the tx is charged for a portion of totalMissingFee
|
|
218
218
|
actualFee = totalMissingFee.mul(maxFee).div(totalDynamicFee);
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
if (actualFee.
|
|
221
|
+
if (actualFee.isNeg()) {
|
|
222
222
|
throw new Error('NEGATIVE_ACTUAL_FEE', 'Got negative actualFee for tx, abort!');
|
|
223
223
|
}
|
|
224
224
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.18.0",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -21,17 +21,17 @@
|
|
|
21
21
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@arcblock/did": "1.
|
|
25
|
-
"@arcblock/did-util": "1.
|
|
26
|
-
"@arcblock/validator": "1.
|
|
27
|
-
"@ocap/asset": "1.
|
|
28
|
-
"@ocap/mcrypto": "1.
|
|
29
|
-
"@ocap/merkle-tree": "1.
|
|
30
|
-
"@ocap/message": "1.
|
|
31
|
-
"@ocap/state": "1.
|
|
32
|
-
"@ocap/tx-pipeline": "1.
|
|
33
|
-
"@ocap/util": "1.
|
|
34
|
-
"@ocap/wallet": "1.
|
|
24
|
+
"@arcblock/did": "1.18.0",
|
|
25
|
+
"@arcblock/did-util": "1.18.0",
|
|
26
|
+
"@arcblock/validator": "1.18.0",
|
|
27
|
+
"@ocap/asset": "1.18.0",
|
|
28
|
+
"@ocap/mcrypto": "1.18.0",
|
|
29
|
+
"@ocap/merkle-tree": "1.18.0",
|
|
30
|
+
"@ocap/message": "1.18.0",
|
|
31
|
+
"@ocap/state": "1.18.0",
|
|
32
|
+
"@ocap/tx-pipeline": "1.18.0",
|
|
33
|
+
"@ocap/util": "1.18.0",
|
|
34
|
+
"@ocap/wallet": "1.18.0",
|
|
35
35
|
"debug": "^4.3.4",
|
|
36
36
|
"deep-diff": "^1.0.2",
|
|
37
37
|
"empty-value": "^1.0.1",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"jest": "^27.5.1",
|
|
47
47
|
"start-server-and-test": "^1.14.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "c48f928ee4f0deddf0f5e4bcb82fd6ffd7f2bc99"
|
|
50
50
|
}
|