@ocap/tx-protocols 1.13.62 → 1.13.66
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/protocols/account/declare.js +2 -1
- package/lib/protocols/account/delegate.js +23 -6
- package/lib/protocols/account/migrate.js +4 -3
- package/lib/protocols/account/revoke-delegate.js +4 -4
- package/lib/protocols/asset/acquire-v2.js +3 -2
- package/lib/protocols/asset/acquire-v3.js +47 -37
- package/lib/protocols/asset/create.js +21 -8
- package/lib/protocols/asset/mint.js +19 -8
- package/lib/protocols/asset/pipes/verify-itx-address.js +3 -3
- package/lib/protocols/asset/update.js +7 -2
- package/lib/protocols/factory/create.js +20 -16
- package/lib/protocols/governance/claim-stake.js +3 -2
- package/lib/protocols/governance/stake.js +3 -2
- package/lib/protocols/rollup/claim-reward.js +4 -3
- package/lib/protocols/rollup/create-block.js +8 -7
- package/lib/protocols/rollup/create.js +16 -3
- package/lib/protocols/rollup/join.js +4 -3
- package/lib/protocols/rollup/leave.js +4 -3
- package/lib/protocols/rollup/pipes/ensure-tx-fee.js +38 -0
- package/lib/protocols/rollup/update.js +2 -1
- package/lib/protocols/token/create.js +18 -8
- package/lib/protocols/token/deposit-v2.js +26 -20
- package/lib/protocols/token/withdraw-v2.js +6 -5
- package/lib/protocols/trade/exchange-v2.js +6 -6
- package/lib/protocols/trade/transfer-v2.js +21 -13
- package/lib/protocols/trade/transfer-v3.js +27 -13
- package/lib/util.js +1 -1
- package/package.json +13 -12
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
2
3
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
3
|
-
const { account
|
|
4
|
+
const { account } = require('@ocap/state');
|
|
4
5
|
const { toBase58 } = require('@ocap/util');
|
|
5
6
|
|
|
6
7
|
const runner = new Runner();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
2
|
const get = require('lodash/get');
|
|
3
|
+
const Joi = require('@ocap/validator');
|
|
3
4
|
const Error = require('@ocap/util/lib/error');
|
|
4
5
|
const getListField = require('@ocap/util/lib/get-list-field');
|
|
5
|
-
const { delegation, account
|
|
6
|
+
const { delegation, account } = require('@ocap/state');
|
|
6
7
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
7
8
|
const { toDelegateAddress } = require('@arcblock/did-util');
|
|
8
9
|
|
|
@@ -61,9 +62,9 @@ runner.use(
|
|
|
61
62
|
);
|
|
62
63
|
|
|
63
64
|
// Ensure sender/receiver exist
|
|
64
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: '
|
|
65
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK', table: 'account' }));
|
|
65
66
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
66
|
-
runner.use(pipes.ExtractState({ from: 'itx.to', to: 'receiverState', status: '
|
|
67
|
+
runner.use(pipes.ExtractState({ from: 'itx.to', to: 'receiverState', status: 'OK', table: 'account' }));
|
|
67
68
|
|
|
68
69
|
// Extract delegation
|
|
69
70
|
runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', table: 'delegation', status: 'OK' }));
|
|
@@ -71,7 +72,7 @@ runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', tabl
|
|
|
71
72
|
// Create delegation state
|
|
72
73
|
runner.use(
|
|
73
74
|
async (context, next) => {
|
|
74
|
-
const { tx, itx, ops, statedb, senderState, delegationState } = context;
|
|
75
|
+
const { tx, itx, ops, statedb, senderState, receiverState, delegationState } = context;
|
|
75
76
|
|
|
76
77
|
const opsObj = ops.reduce(
|
|
77
78
|
(acc, x) => {
|
|
@@ -86,8 +87,23 @@ runner.use(
|
|
|
86
87
|
delegationState ? delegationState.ops : {}
|
|
87
88
|
);
|
|
88
89
|
|
|
89
|
-
const
|
|
90
|
-
|
|
90
|
+
const sender = senderState ? senderState.address : tx.from;
|
|
91
|
+
const receiver = receiverState ? receiverState.address : itx.to;
|
|
92
|
+
|
|
93
|
+
const [newSenderState, newReceiverState, newDelegationState] = await Promise.all([
|
|
94
|
+
// update sender
|
|
95
|
+
statedb.account.updateOrCreate(
|
|
96
|
+
senderState,
|
|
97
|
+
account.updateOrCreate(senderState, { address: sender, nonce: tx.nonce, pk: tx.pk }, context),
|
|
98
|
+
context
|
|
99
|
+
),
|
|
100
|
+
|
|
101
|
+
// update receiver
|
|
102
|
+
receiverState
|
|
103
|
+
? Promise.resolve(receiverState)
|
|
104
|
+
: statedb.account.create(receiver, account.create({ address: receiver }, context), context),
|
|
105
|
+
|
|
106
|
+
// update delegation
|
|
91
107
|
delegationState
|
|
92
108
|
? statedb.delegation.update(itx.address, delegation.update(delegationState, { ...itx, ops: opsObj }, context), context) // prettier-ignore
|
|
93
109
|
: statedb.delegation.create(itx.address, delegation.create({ ...itx, ops: opsObj }, context), context),
|
|
@@ -97,6 +113,7 @@ runner.use(
|
|
|
97
113
|
|
|
98
114
|
// Update context
|
|
99
115
|
context.senderState = newSenderState;
|
|
116
|
+
context.receiverState = newReceiverState;
|
|
100
117
|
context.delegationState = newDelegationState;
|
|
101
118
|
|
|
102
119
|
return next();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
2
3
|
const getRelatedAddresses = require('@ocap/util/lib/get-related-addr');
|
|
3
4
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
5
|
const { fromPublicKey, toTypeInfo } = require('@arcblock/did');
|
|
5
|
-
const { account
|
|
6
|
+
const { account } = require('@ocap/state');
|
|
6
7
|
|
|
7
8
|
// eslint-disable-next-line global-require
|
|
8
9
|
const debug = require('debug')(`${require('../../../package.json').name}:migrate`);
|
|
@@ -35,7 +36,7 @@ runner.use(
|
|
|
35
36
|
);
|
|
36
37
|
|
|
37
38
|
// Ensure sender exist
|
|
38
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
39
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
39
40
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
40
41
|
|
|
41
42
|
// Create account state, and update old accounts
|
|
@@ -48,7 +49,7 @@ runner.use(
|
|
|
48
49
|
|
|
49
50
|
// Ensure receiver does not exist
|
|
50
51
|
if (receiver) {
|
|
51
|
-
return next(new Error('
|
|
52
|
+
return next(new Error('INVALID_RECEIVER_STATE', 'Can not migrate to an existing account'));
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
// Create new account
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const get = require('lodash/get');
|
|
2
2
|
const cloneDeep = require('lodash/cloneDeep');
|
|
3
|
+
const Joi = require('@ocap/validator');
|
|
3
4
|
const getListField = require('@ocap/util/lib/get-list-field');
|
|
4
5
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
5
|
-
const { delegation, account
|
|
6
|
+
const { delegation, account } = require('@ocap/state');
|
|
6
7
|
const { toDelegateAddress } = require('@arcblock/did-util');
|
|
7
8
|
|
|
8
9
|
// eslint-disable-next-line global-require
|
|
@@ -53,10 +54,9 @@ runner.use(
|
|
|
53
54
|
);
|
|
54
55
|
|
|
55
56
|
// Ensure sender/receiver/delegation exist
|
|
56
|
-
runner.use(pipes.ExtractState({ from: '
|
|
57
|
+
runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', status: 'INVALID_DELEGATION', table: 'delegation' })); // prettier-ignore
|
|
58
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
57
59
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
58
|
-
runner.use(pipes.ExtractState({ from: 'itx.to', to: 'receiverState', status: 'INVALID_RECEIVER_STATE' }));
|
|
59
|
-
runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', status: 'INVALID_DELEGATION' }));
|
|
60
60
|
|
|
61
61
|
// Update delegation state
|
|
62
62
|
runner.use(
|
|
@@ -24,7 +24,7 @@ const runner = new Runner();
|
|
|
24
24
|
runner.use(pipes.VerifyMultiSig(0));
|
|
25
25
|
runner.use(verifyAcquireParams('acquire-v2'));
|
|
26
26
|
|
|
27
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
27
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
28
28
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
29
29
|
|
|
30
30
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK' }));
|
|
@@ -43,7 +43,7 @@ runner.use(
|
|
|
43
43
|
|
|
44
44
|
// Though tokens are verified on factory creating phase, we need them here to construct tokenSymbols
|
|
45
45
|
runner.use(extractFactoryTokens);
|
|
46
|
-
runner.use(pipes.ExtractState({ from: 'tokenAddress', to: 'tokenStates', status: 'INVALID_TOKEN' }));
|
|
46
|
+
runner.use(pipes.ExtractState({ from: 'tokenAddress', to: 'tokenStates', status: 'INVALID_TOKEN', table: 'token' }));
|
|
47
47
|
|
|
48
48
|
// Verify itx
|
|
49
49
|
runner.use(verifyMintLimit);
|
|
@@ -86,6 +86,7 @@ runner.use(
|
|
|
86
86
|
// Sender updates
|
|
87
87
|
const senderUpdates = {
|
|
88
88
|
nonce: tx.nonce,
|
|
89
|
+
pk: tx.pk,
|
|
89
90
|
...applyTokenUpdates(factoryTokens, senderState, 'sub'),
|
|
90
91
|
};
|
|
91
92
|
|
|
@@ -82,9 +82,9 @@ runner.use(
|
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
// 5. verify sender & signer & owner
|
|
85
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
86
|
-
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE' }));
|
|
87
|
-
runner.use(pipes.ExtractState({ from: 'itx.owner', to: 'ownerState', status: '
|
|
85
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
86
|
+
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
87
|
+
runner.use(pipes.ExtractState({ from: 'itx.owner', to: 'ownerState', status: 'OK', table: 'account' }));
|
|
88
88
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
89
89
|
|
|
90
90
|
// 6. verify token state and balance
|
|
@@ -153,6 +153,7 @@ runner.use(
|
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
const isAlsoSigner = !!signerUpdates[senderState.address];
|
|
156
|
+
const owner = ownerState ? ownerState.address : itx.owner;
|
|
156
157
|
|
|
157
158
|
// Factory updates
|
|
158
159
|
const factoryUpdates = { numMinted: factoryState.numMinted + 1 };
|
|
@@ -163,44 +164,53 @@ runner.use(
|
|
|
163
164
|
context.tokenUpdates = applyTokenUpdates(factoryTokens, { tokens: {} }, 'add');
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
const [newSenderState, assetState, newSignerStates, newFactoryState, newAssetStates] =
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
const [newSenderState, newReceiverState, assetState, newSignerStates, newFactoryState, newAssetStates] =
|
|
168
|
+
await Promise.all([
|
|
169
|
+
// Update sender state
|
|
170
|
+
statedb.account.update(
|
|
171
|
+
senderState.address,
|
|
172
|
+
account.update(
|
|
173
|
+
senderState,
|
|
174
|
+
Object.assign({ nonce: tx.nonce, pk: tx.pk }, signerUpdates[senderState.address] || {}),
|
|
175
|
+
context
|
|
176
|
+
),
|
|
173
177
|
context
|
|
174
178
|
),
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
179
|
+
|
|
180
|
+
// create receiver if not exist: asset owner
|
|
181
|
+
ownerState
|
|
182
|
+
? Promise.resolve(ownerState)
|
|
183
|
+
: statedb.account.create(owner, account.create({ address: owner }, context), context),
|
|
184
|
+
|
|
185
|
+
// Create asset
|
|
186
|
+
statedb.asset.create(
|
|
187
|
+
itx.address,
|
|
188
|
+
asset.create({ ...mintedAsset, owner, address: mintedAddress }, context),
|
|
189
|
+
context
|
|
190
|
+
),
|
|
191
|
+
|
|
192
|
+
// Update signer state
|
|
193
|
+
Promise.all(
|
|
194
|
+
signerStates
|
|
195
|
+
.filter((x) => x.address !== senderState.address)
|
|
196
|
+
.map((x) =>
|
|
197
|
+
statedb.account.update(x.address, account.update(x, signerUpdates[x.address], context), context)
|
|
198
|
+
)
|
|
199
|
+
),
|
|
200
|
+
|
|
201
|
+
// Update factory state
|
|
202
|
+
statedb.factory.update(factoryState.address, factory.update(factoryState, factoryUpdates, context), context),
|
|
203
|
+
|
|
204
|
+
// Mark asset as consumed
|
|
205
|
+
Promise.all(
|
|
206
|
+
assetStates.map((x) =>
|
|
207
|
+
statedb.asset.update(x.address, asset.update(x, { consumedTime: txTime }, context), context)
|
|
208
|
+
)
|
|
209
|
+
),
|
|
210
|
+
]);
|
|
202
211
|
|
|
203
212
|
context.senderState = newSenderState;
|
|
213
|
+
context.receiverState = newReceiverState;
|
|
204
214
|
context.signerStates = isAlsoSigner ? newSignerStates.concat(newSenderState) : newSignerStates;
|
|
205
215
|
context.assetState = assetState;
|
|
206
216
|
context.factoryState = newFactoryState;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/* eslint-disable indent */
|
|
2
2
|
const Error = require('@ocap/util/lib/error');
|
|
3
|
+
const isEmpty = require('lodash/isEmpty');
|
|
3
4
|
const cloneDeep = require('lodash/cloneDeep');
|
|
5
|
+
const Joi = require('@ocap/validator');
|
|
4
6
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
5
|
-
const { account, asset
|
|
7
|
+
const { account, asset } = require('@ocap/state');
|
|
6
8
|
const { toAssetAddress } = require('@arcblock/did-util');
|
|
7
9
|
|
|
8
10
|
// eslint-disable-next-line global-require
|
|
9
11
|
const debug = require('debug')(`${require('../../../package.json').name}:create-asset`);
|
|
10
12
|
|
|
11
13
|
const { decodeAnySafe } = require('../../util');
|
|
14
|
+
const ensureTxFee = require('../rollup/pipes/ensure-tx-fee');
|
|
12
15
|
|
|
13
16
|
const runner = new Runner();
|
|
14
17
|
|
|
@@ -64,7 +67,7 @@ runner.use(
|
|
|
64
67
|
);
|
|
65
68
|
|
|
66
69
|
// Ensure sender exist
|
|
67
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
70
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
68
71
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
69
72
|
|
|
70
73
|
// Check if parent is a factory
|
|
@@ -83,26 +86,36 @@ runner.use(
|
|
|
83
86
|
);
|
|
84
87
|
|
|
85
88
|
// Ensure parent exist
|
|
86
|
-
runner.use(pipes.ExtractState({ from: 'itx.parent', to: 'parentAsset', status: 'INVALID_ASSET' }));
|
|
89
|
+
runner.use(pipes.ExtractState({ from: 'itx.parent', to: 'parentAsset', status: 'INVALID_ASSET', table: 'asset' }));
|
|
90
|
+
|
|
91
|
+
runner.use(ensureTxFee);
|
|
87
92
|
|
|
88
93
|
// Update asset state
|
|
89
94
|
runner.use(
|
|
90
95
|
async (context, next) => {
|
|
91
|
-
const { tx, itx, assetData, statedb, senderState } = context;
|
|
96
|
+
const { tx, itx, assetData, statedb, senderState, senderUpdates, vaultState, vaultUpdates } = context;
|
|
97
|
+
|
|
98
|
+
const [newSenderState, assetState, newVaultState] = await Promise.all([
|
|
99
|
+
statedb.account.update(
|
|
100
|
+
senderState.address,
|
|
101
|
+
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
102
|
+
context
|
|
103
|
+
),
|
|
92
104
|
|
|
93
|
-
const [newSenderState, assetState] = await Promise.all([
|
|
94
|
-
// Update owner state
|
|
95
|
-
statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
|
|
96
|
-
// Create asset state
|
|
97
105
|
statedb.asset.create(
|
|
98
106
|
itx.address,
|
|
99
107
|
asset.create({ ...itx, data: assetData, owner: senderState.address }, context),
|
|
100
108
|
context
|
|
101
109
|
),
|
|
110
|
+
|
|
111
|
+
isEmpty(vaultUpdates)
|
|
112
|
+
? vaultState
|
|
113
|
+
: statedb.account.update(vaultState.address, account.update(vaultState, vaultUpdates, context), context),
|
|
102
114
|
]);
|
|
103
115
|
|
|
104
116
|
context.senderState = newSenderState;
|
|
105
117
|
context.assetState = assetState;
|
|
118
|
+
context.vaultState = newVaultState;
|
|
106
119
|
|
|
107
120
|
debug('createAsset', assetState);
|
|
108
121
|
|
|
@@ -17,17 +17,17 @@ runner.use(pipes.VerifyMultiSig(0));
|
|
|
17
17
|
runner.use(verifyAcquireParams('mint'));
|
|
18
18
|
|
|
19
19
|
// Ensure sender exist
|
|
20
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
20
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
21
21
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
22
22
|
|
|
23
23
|
// Ensure factory exist
|
|
24
24
|
runner.use(pipes.ExtractState({ from: 'itx.factory', to: 'factoryState', status: 'INVALID_FACTORY_STATE', table: 'factory' })); // prettier-ignore
|
|
25
25
|
|
|
26
26
|
// Used to assemble issuer object
|
|
27
|
-
runner.use(pipes.ExtractState({ from: 'factoryState.owner', to: 'factoryOwnerState', status: 'INVALID_OWNER' }));
|
|
27
|
+
runner.use(pipes.ExtractState({ from: 'factoryState.owner', to: 'factoryOwnerState', status: 'INVALID_OWNER', table: 'account' })); // prettier-ignore
|
|
28
28
|
|
|
29
29
|
// Ensure factory owner exist and equal to sender
|
|
30
|
-
runner.use(pipes.ExtractState({ from: 'itx.owner', to: 'ownerState', status: '
|
|
30
|
+
runner.use(pipes.ExtractState({ from: 'itx.owner', to: 'ownerState', status: 'OK', table: 'account' }));
|
|
31
31
|
runner.use(
|
|
32
32
|
pipes.VerifyInfo([
|
|
33
33
|
{
|
|
@@ -72,20 +72,30 @@ runner.use(
|
|
|
72
72
|
assetStates = [],
|
|
73
73
|
} = context;
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
const senderUpdates = { nonce: tx.nonce };
|
|
75
|
+
const owner = ownerState ? ownerState.address : itx.owner;
|
|
77
76
|
|
|
78
|
-
|
|
77
|
+
const senderUpdates = { nonce: tx.nonce, pk: tx.pk };
|
|
79
78
|
const factoryUpdates = { numMinted: factoryState.numMinted + 1 };
|
|
80
79
|
|
|
81
|
-
const [newSenderState, assetState, newFactoryState, newAssetStates] = await Promise.all([
|
|
80
|
+
const [newSenderState, newReceiverState, assetState, newFactoryState, newAssetStates] = await Promise.all([
|
|
81
|
+
// update sender
|
|
82
82
|
statedb.account.update(senderState.address, account.update(senderState, senderUpdates, context), context),
|
|
83
|
+
|
|
84
|
+
// create receiver if not exist: asset owner
|
|
85
|
+
ownerState
|
|
86
|
+
? Promise.resolve(ownerState)
|
|
87
|
+
: statedb.account.create(owner, account.create({ address: owner }, context), context),
|
|
88
|
+
|
|
89
|
+
// create asset
|
|
83
90
|
statedb.asset.create(
|
|
84
91
|
itx.address,
|
|
85
|
-
asset.create({ ...mintedAsset, owner
|
|
92
|
+
asset.create({ ...mintedAsset, owner, address: mintedAddress }, context),
|
|
86
93
|
context
|
|
87
94
|
),
|
|
95
|
+
|
|
96
|
+
// update factory
|
|
88
97
|
statedb.factory.update(factoryState.address, factory.update(factoryState, factoryUpdates, context), context),
|
|
98
|
+
|
|
89
99
|
// mark input assets as consumed
|
|
90
100
|
Promise.all(
|
|
91
101
|
assetStates.map((x) =>
|
|
@@ -95,6 +105,7 @@ runner.use(
|
|
|
95
105
|
]);
|
|
96
106
|
|
|
97
107
|
context.senderState = newSenderState;
|
|
108
|
+
context.receiverState = newReceiverState;
|
|
98
109
|
context.assetState = assetState;
|
|
99
110
|
context.factoryState = newFactoryState;
|
|
100
111
|
context.assetStates = newAssetStates;
|
|
@@ -10,11 +10,12 @@ module.exports = (mode) => (context, next) => {
|
|
|
10
10
|
if (mode === 'acquire-v2') {
|
|
11
11
|
owner = delegatorState || senderState;
|
|
12
12
|
issuer = itx.issuer;
|
|
13
|
+
context.assetOwner = owner;
|
|
13
14
|
} else if (mode === 'acquire-v3') {
|
|
14
|
-
owner = ownerState;
|
|
15
|
+
owner = ownerState || { address: itx.owner };
|
|
15
16
|
issuer = itx.issuer;
|
|
16
17
|
} else if (mode === 'mint') {
|
|
17
|
-
owner = ownerState;
|
|
18
|
+
owner = ownerState || { address: itx.owner };
|
|
18
19
|
issuer = {
|
|
19
20
|
id: factoryOwnerState.address,
|
|
20
21
|
pk: factoryOwnerState.pk,
|
|
@@ -33,7 +34,6 @@ module.exports = (mode) => (context, next) => {
|
|
|
33
34
|
return next(new Error('INVALID_ASSET', 'Invalid itx.address: does not match with minted asset address'));
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
context.assetOwner = owner;
|
|
37
37
|
context.mintedAsset = minted.asset;
|
|
38
38
|
context.mintedAddress = minted.address;
|
|
39
39
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
2
3
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
3
|
-
const { account, asset
|
|
4
|
+
const { account, asset } = require('@ocap/state');
|
|
4
5
|
|
|
5
6
|
// eslint-disable-next-line global-require
|
|
6
7
|
const debug = require('debug')(`${require('../../../package.json').name}:update-asset`);
|
|
@@ -52,7 +53,11 @@ runner.use(
|
|
|
52
53
|
|
|
53
54
|
const [newSenderState, newAssetState] = await Promise.all([
|
|
54
55
|
// update owner state
|
|
55
|
-
statedb.account.update(
|
|
56
|
+
statedb.account.update(
|
|
57
|
+
senderState.address,
|
|
58
|
+
account.update(senderState, { nonce: tx.nonce, pk: tx.pk }, context),
|
|
59
|
+
context
|
|
60
|
+
),
|
|
56
61
|
|
|
57
62
|
// update asset state
|
|
58
63
|
statedb.asset.update(
|
|
@@ -14,6 +14,7 @@ const { toFactoryAddress } = require('@arcblock/did-util');
|
|
|
14
14
|
const debug = require('debug')(`${require('../../../package.json').name}:create-factory`);
|
|
15
15
|
|
|
16
16
|
const { decodeAnySafe } = require('../../util');
|
|
17
|
+
const ensureTxFee = require('../rollup/pipes/ensure-tx-fee');
|
|
17
18
|
|
|
18
19
|
const runner = new Runner();
|
|
19
20
|
|
|
@@ -79,23 +80,15 @@ runner.use(
|
|
|
79
80
|
);
|
|
80
81
|
|
|
81
82
|
// Ensure sender exist
|
|
82
|
-
runner.use(
|
|
83
|
-
pipes.ExtractState({ from: 'tx.from', to: 'senderState', table: 'account', status: 'INVALID_SENDER_STATE' })
|
|
84
|
-
);
|
|
83
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', table: 'account', status: 'INVALID_SENDER_STATE' })); // prettier-ignore
|
|
85
84
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
86
85
|
|
|
87
86
|
// Ensure tokens exist if we are creating an factory that consume tokens
|
|
88
|
-
runner.use(
|
|
89
|
-
pipes.ExtractState({ from: 'factoryTokens', to: 'tokenStates', table: 'token', status: 'INVALID_FACTORY_INPUT' })
|
|
90
|
-
);
|
|
87
|
+
runner.use(pipes.ExtractState({ from: 'factoryTokens', to: 'tokenStates', table: 'token', status: 'INVALID_FACTORY_INPUT' })); // prettier-ignore
|
|
91
88
|
|
|
92
89
|
// ensure input.assets all exist on chain
|
|
93
|
-
runner.use(
|
|
94
|
-
|
|
95
|
-
);
|
|
96
|
-
runner.use(
|
|
97
|
-
pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputFactoryStates', table: 'factory', status: 'OK' })
|
|
98
|
-
);
|
|
90
|
+
runner.use(pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputAssetStates', table: 'asset', status: 'OK' })); // prettier-ignore
|
|
91
|
+
runner.use(pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputFactoryStates', table: 'factory', status: 'OK' })); // prettier-ignore
|
|
99
92
|
runner.use((context, next) => {
|
|
100
93
|
const { inputAssetStates = [], inputFactoryStates = [], factoryProps } = context;
|
|
101
94
|
if (inputAssetStates.some((x) => !!x.consumedTime)) {
|
|
@@ -109,26 +102,37 @@ runner.use((context, next) => {
|
|
|
109
102
|
return next(new Error('INVALID_FACTORY_INPUT', 'Not all input.assets exist on chain'));
|
|
110
103
|
});
|
|
111
104
|
|
|
105
|
+
runner.use(ensureTxFee);
|
|
106
|
+
|
|
112
107
|
// Create factory state
|
|
113
|
-
// TODO: we need to support charging when creating new nft-factory
|
|
114
108
|
runner.use(
|
|
115
109
|
async (context, next) => {
|
|
116
|
-
const { tx, itx, statedb, senderState, factoryProps } = context;
|
|
110
|
+
const { tx, itx, statedb, senderState, senderUpdates, vaultState, vaultUpdates, factoryProps } = context;
|
|
117
111
|
const tokens = { [context.config.token.address]: '0' };
|
|
118
112
|
|
|
119
|
-
const [newSenderState, factoryState] = await Promise.all([
|
|
113
|
+
const [newSenderState, factoryState, newVaultState] = await Promise.all([
|
|
120
114
|
// Update owner state
|
|
121
|
-
statedb.account.update(
|
|
115
|
+
statedb.account.update(
|
|
116
|
+
senderState.address,
|
|
117
|
+
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
118
|
+
context
|
|
119
|
+
),
|
|
120
|
+
|
|
122
121
|
// Create factory state
|
|
123
122
|
statedb.factory.create(
|
|
124
123
|
itx.address,
|
|
125
124
|
factory.create({ ...factoryProps, tokens, owner: senderState.address }, context),
|
|
126
125
|
context
|
|
127
126
|
),
|
|
127
|
+
|
|
128
|
+
isEmpty(vaultUpdates)
|
|
129
|
+
? vaultState
|
|
130
|
+
: statedb.account.update(vaultState.address, account.update(vaultState, vaultUpdates, context), context),
|
|
128
131
|
]);
|
|
129
132
|
|
|
130
133
|
context.senderState = newSenderState;
|
|
131
134
|
context.factoryState = factoryState;
|
|
135
|
+
context.vaultState = newVaultState;
|
|
132
136
|
|
|
133
137
|
debug('createFactory', factoryState);
|
|
134
138
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
2
3
|
const { BN } = require('@ocap/util');
|
|
3
4
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
-
const { account, asset, stake, evidence
|
|
5
|
+
const { account, asset, stake, evidence } = require('@ocap/state');
|
|
5
6
|
|
|
6
7
|
// eslint-disable-next-line global-require
|
|
7
8
|
const debug = require('debug')(`${require('../../../package.json').name}:acquire-asset-v2`);
|
|
@@ -16,7 +17,7 @@ runner.use(pipes.VerifyMultiSig(0));
|
|
|
16
17
|
const schema = Joi.object({
|
|
17
18
|
address: Joi.DID().role('ROLE_STAKE').required(),
|
|
18
19
|
evidence: Joi.object({
|
|
19
|
-
hash: Joi.string().regex(Joi.
|
|
20
|
+
hash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
20
21
|
}).required(),
|
|
21
22
|
data: Joi.any().optional(),
|
|
22
23
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const pick = require('lodash/pick');
|
|
2
2
|
const { promisify } = require('util');
|
|
3
3
|
const isEmpty = require('empty-value');
|
|
4
|
+
const Joi = require('@ocap/validator');
|
|
4
5
|
const Error = require('@ocap/util/lib/error');
|
|
5
6
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
6
7
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
7
|
-
const { account, asset, stake
|
|
8
|
+
const { account, asset, stake } = require('@ocap/state');
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line global-require
|
|
10
11
|
const debug = require('debug')(`${require('../../../package.json').name}:acquire-asset-v2`);
|
|
@@ -122,7 +123,7 @@ runner.use(
|
|
|
122
123
|
senderState.address,
|
|
123
124
|
account.update(
|
|
124
125
|
senderState,
|
|
125
|
-
Object.assign({ nonce: tx.nonce }, signerUpdates[senderState.address] || {}),
|
|
126
|
+
Object.assign({ nonce: tx.nonce, pk: tx.pk }, signerUpdates[senderState.address] || {}),
|
|
126
127
|
context
|
|
127
128
|
),
|
|
128
129
|
context
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const uniqBy = require('lodash/uniqBy');
|
|
2
2
|
const groupBy = require('lodash/groupBy');
|
|
3
3
|
const cloneDeep = require('lodash/cloneDeep');
|
|
4
|
+
const Joi = require('@ocap/validator');
|
|
4
5
|
const Error = require('@ocap/util/lib/error');
|
|
5
6
|
const { BN } = require('@ocap/util');
|
|
6
7
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
7
|
-
const { account, stake, evidence, rollupBlock
|
|
8
|
+
const { account, stake, evidence, rollupBlock } = require('@ocap/state');
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line global-require
|
|
10
11
|
const debug = require('debug')(`${require('../../../package.json').name}:claim-block-reward`);
|
|
@@ -19,9 +20,9 @@ const runner = new Runner();
|
|
|
19
20
|
const schema = Joi.object({
|
|
20
21
|
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
21
22
|
blockHeight: Joi.number().integer().greater(0).required(),
|
|
22
|
-
blockHash: Joi.string().regex(Joi.
|
|
23
|
+
blockHash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
23
24
|
evidence: Joi.object({
|
|
24
|
-
hash: Joi.string().regex(Joi.
|
|
25
|
+
hash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
25
26
|
}).required(),
|
|
26
27
|
publisher: Joi.DID().wallet('ethereum').required(),
|
|
27
28
|
data: Joi.any().optional(),
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
const pick = require('lodash/pick');
|
|
3
3
|
const Error = require('@ocap/util/lib/error');
|
|
4
4
|
const MerkleTree = require('@ocap/merkle-tree');
|
|
5
|
+
const Joi = require('@ocap/validator');
|
|
5
6
|
const { formatMessage } = require('@ocap/message');
|
|
6
7
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
7
8
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
8
|
-
const { account, stake, rollup, rollupBlock, tx: Tx
|
|
9
|
+
const { account, stake, rollup, rollupBlock, tx: Tx } = require('@ocap/state');
|
|
9
10
|
|
|
10
11
|
// eslint-disable-next-line global-require
|
|
11
12
|
const debug = require('debug')(`${require('../../../package.json').name}:create-rollup-block`);
|
|
@@ -19,18 +20,18 @@ const runner = new Runner();
|
|
|
19
20
|
|
|
20
21
|
// 1. verify itx
|
|
21
22
|
const schema = Joi.object({
|
|
22
|
-
hash: Joi.string().regex(Joi.
|
|
23
|
+
hash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
23
24
|
height: Joi.number().integer().greater(0).required(),
|
|
24
|
-
merkleRoot: Joi.string().regex(Joi.
|
|
25
|
+
merkleRoot: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
25
26
|
previousHash: Joi.string().when('height', {
|
|
26
27
|
is: 1,
|
|
27
28
|
then: Joi.string().optional().allow(''),
|
|
28
|
-
otherwise: Joi.string().regex(Joi.
|
|
29
|
+
otherwise: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
29
30
|
}),
|
|
30
|
-
txsHash: Joi.string().regex(Joi.
|
|
31
|
-
txsList: Joi.array().items(Joi.string().regex(Joi.
|
|
31
|
+
txsHash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
32
|
+
txsList: Joi.array().items(Joi.string().regex(Joi.patterns.txHash).required()).min(1).unique().required(),
|
|
32
33
|
proposer: Joi.DID().wallet('ethereum').required(),
|
|
33
|
-
signaturesList: Joi.
|
|
34
|
+
signaturesList: Joi.schemas.multiSig.min(1).required(),
|
|
34
35
|
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
35
36
|
minReward: Joi.BN().min(0).required(),
|
|
36
37
|
data: Joi.any().optional(),
|
|
@@ -12,6 +12,7 @@ const { toRollupAddress } = require('@arcblock/did-util');
|
|
|
12
12
|
const debug = require('debug')(`${require('../../../package.json').name}:create-rollup`);
|
|
13
13
|
|
|
14
14
|
const { decodeAnySafe } = require('../../util');
|
|
15
|
+
const ensureTxFee = require('./pipes/ensure-tx-fee');
|
|
15
16
|
|
|
16
17
|
const runner = new Runner();
|
|
17
18
|
|
|
@@ -105,13 +106,20 @@ runner.use(
|
|
|
105
106
|
])
|
|
106
107
|
);
|
|
107
108
|
|
|
109
|
+
runner.use(ensureTxFee);
|
|
110
|
+
|
|
108
111
|
// 5. create rollup state
|
|
109
112
|
runner.use(
|
|
110
113
|
async (context, next) => {
|
|
111
|
-
const { tx, formattedItx, rollupData, statedb, senderState } = context;
|
|
114
|
+
const { tx, formattedItx, rollupData, statedb, senderState, senderUpdates, vaultState, vaultUpdates } = context;
|
|
115
|
+
|
|
116
|
+
const [newSenderState, rollupState, newVaultState] = await Promise.all([
|
|
117
|
+
statedb.account.update(
|
|
118
|
+
senderState.address,
|
|
119
|
+
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
120
|
+
context
|
|
121
|
+
),
|
|
112
122
|
|
|
113
|
-
const [newSenderState, rollupState] = await Promise.all([
|
|
114
|
-
statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
|
|
115
123
|
statedb.rollup.create(
|
|
116
124
|
formattedItx.address,
|
|
117
125
|
rollup.create(
|
|
@@ -128,6 +136,10 @@ runner.use(
|
|
|
128
136
|
),
|
|
129
137
|
context
|
|
130
138
|
),
|
|
139
|
+
|
|
140
|
+
isEmpty(vaultUpdates)
|
|
141
|
+
? vaultState
|
|
142
|
+
: statedb.account.update(vaultState.address, account.update(vaultState, vaultUpdates, context), context),
|
|
131
143
|
]);
|
|
132
144
|
|
|
133
145
|
// FIXME: create-rollup 的时候不能校验 stake,还是在这里创建 stake?如果在这里创建 stake,是否需要多签?
|
|
@@ -135,6 +147,7 @@ runner.use(
|
|
|
135
147
|
|
|
136
148
|
context.senderState = newSenderState;
|
|
137
149
|
context.rollupState = rollupState;
|
|
150
|
+
context.vaultState = newVaultState;
|
|
138
151
|
|
|
139
152
|
debug('create-rollup', rollupState);
|
|
140
153
|
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
const MerkleTree = require('@ocap/merkle-tree');
|
|
3
3
|
const joinUrl = require('url-join');
|
|
4
4
|
const Error = require('@ocap/util/lib/error');
|
|
5
|
+
const Joi = require('@ocap/validator');
|
|
5
6
|
const { BN, toHex } = require('@ocap/util');
|
|
6
7
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
7
|
-
const { account, rollup, stake, evidence
|
|
8
|
+
const { account, rollup, stake, evidence } = require('@ocap/state');
|
|
8
9
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
9
10
|
const { isEthereumDid } = require('@arcblock/did');
|
|
10
11
|
|
|
@@ -24,9 +25,9 @@ const schema = Joi.object({
|
|
|
24
25
|
.uri({ scheme: [/https?/] })
|
|
25
26
|
.required(),
|
|
26
27
|
evidence: Joi.object({
|
|
27
|
-
hash: Joi.string().regex(Joi.
|
|
28
|
+
hash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
28
29
|
}).required(),
|
|
29
|
-
signaturesList: Joi.
|
|
30
|
+
signaturesList: Joi.schemas.multiSig.min(1).required(),
|
|
30
31
|
data: Joi.any().optional(),
|
|
31
32
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
32
33
|
runner.use(({ itx }, next) => {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable indent */
|
|
2
2
|
const MerkleTree = require('@ocap/merkle-tree');
|
|
3
3
|
const Error = require('@ocap/util/lib/error');
|
|
4
|
+
const Joi = require('@ocap/validator');
|
|
4
5
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
5
|
-
const { account, rollup, stake, evidence
|
|
6
|
+
const { account, rollup, stake, evidence } = require('@ocap/state');
|
|
6
7
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
7
8
|
|
|
8
9
|
// eslint-disable-next-line global-require
|
|
@@ -18,9 +19,9 @@ const runner = new Runner();
|
|
|
18
19
|
const schema = Joi.object({
|
|
19
20
|
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
20
21
|
evidence: Joi.object({
|
|
21
|
-
hash: Joi.string().regex(Joi.
|
|
22
|
+
hash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
22
23
|
}).required(),
|
|
23
|
-
signaturesList: Joi.
|
|
24
|
+
signaturesList: Joi.schemas.multiSig.min(1).required(),
|
|
24
25
|
data: Joi.any().optional(),
|
|
25
26
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
26
27
|
runner.use(({ itx }, next) => {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const { fromTokenToUnit, BN } = require('@ocap/util');
|
|
3
|
+
|
|
4
|
+
const { applyTokenUpdates } = require('../../../util');
|
|
5
|
+
|
|
6
|
+
// FIXME: There maybe bug for tx that decrease senderState token balance
|
|
7
|
+
module.exports = async (context, next) => {
|
|
8
|
+
const { config, statedb, txType, senderState } = context;
|
|
9
|
+
const txFee = config.transaction.txFee[txType];
|
|
10
|
+
const vaultState = await statedb.account.get(config.vaults.txFee, context);
|
|
11
|
+
|
|
12
|
+
if (!txFee) {
|
|
13
|
+
context.senderUpdates = { tokens: {} };
|
|
14
|
+
context.vaultUpdates = { tokens: {} };
|
|
15
|
+
context.vaultState = vaultState;
|
|
16
|
+
context.updatedAccounts = [];
|
|
17
|
+
return next();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const expected = fromTokenToUnit(txFee, config.token.decimal);
|
|
21
|
+
const actual = new BN(senderState.tokens[config.token.address] || 0);
|
|
22
|
+
if (actual.lt(expected)) {
|
|
23
|
+
return next(new Error('INSUFFICIENT_FUND', `Insufficient fund to pay for tx fee, expected ${txFee}`));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const tokenChange = { address: config.token.address, value: expected.toString(10) };
|
|
27
|
+
|
|
28
|
+
context.senderUpdates = applyTokenUpdates([tokenChange], senderState, 'sub');
|
|
29
|
+
context.vaultUpdates = applyTokenUpdates([tokenChange], vaultState, 'add');
|
|
30
|
+
context.vaultState = vaultState;
|
|
31
|
+
|
|
32
|
+
context.updatedAccounts = [
|
|
33
|
+
{ address: senderState.address, token: config.token.address, delta: `-${tokenChange.value}`, action: 'fee' },
|
|
34
|
+
{ address: vaultState.address, token: config.token.address, delta: tokenChange.value, action: 'fee' },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
return next();
|
|
38
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const Error = require('@ocap/util/lib/error');
|
|
2
|
+
const Joi = require('@ocap/validator');
|
|
2
3
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
3
|
-
const { account, rollup
|
|
4
|
+
const { account, rollup } = require('@ocap/state');
|
|
4
5
|
|
|
5
6
|
// eslint-disable-next-line global-require
|
|
6
7
|
const debug = require('debug')(`${require('../../../package.json').name}:update-rollup`);
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
const isEmpty = require('empty-value');
|
|
2
2
|
const cloneDeep = require('lodash/cloneDeep');
|
|
3
|
+
const Joi = require('@ocap/validator');
|
|
3
4
|
const Error = require('@ocap/util/lib/error');
|
|
4
5
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
5
|
-
const { account, token
|
|
6
|
+
const { account, token } = require('@ocap/state');
|
|
6
7
|
const { toTokenAddress } = require('@arcblock/did-util');
|
|
7
8
|
const { fromTokenToUnit } = require('@ocap/util');
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line global-require
|
|
10
11
|
const debug = require('debug')(`${require('../../../package.json').name}:create-token`);
|
|
11
12
|
const { decodeAnySafe } = require('../../util');
|
|
13
|
+
const ensureTxFee = require('../rollup/pipes/ensure-tx-fee');
|
|
12
14
|
|
|
13
15
|
const MAX_TOTAL_SUPPLY = fromTokenToUnit(10000 * 100000000, 18); // 32
|
|
14
16
|
|
|
@@ -26,7 +28,7 @@ const schema = Joi.object({
|
|
|
26
28
|
icon: Joi.string().optional().valid(''),
|
|
27
29
|
totalSupply: Joi.BN().greater(0).max(MAX_TOTAL_SUPPLY).required(),
|
|
28
30
|
initialSupply: Joi.BN().greater(0).max(Joi.ref('totalSupply')).required(),
|
|
29
|
-
foreignToken: Joi.
|
|
31
|
+
foreignToken: Joi.schemas.foreignToken.optional().default(null),
|
|
30
32
|
data: Joi.any().optional(),
|
|
31
33
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
32
34
|
|
|
@@ -56,7 +58,7 @@ runner.use(
|
|
|
56
58
|
);
|
|
57
59
|
|
|
58
60
|
// Ensure sender exist
|
|
59
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
61
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
60
62
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
61
63
|
|
|
62
64
|
// Ensure token not exist
|
|
@@ -86,26 +88,34 @@ runner.use(async (context, next) => {
|
|
|
86
88
|
return next();
|
|
87
89
|
});
|
|
88
90
|
|
|
91
|
+
runner.use(ensureTxFee);
|
|
92
|
+
|
|
89
93
|
// Update sender state, token state
|
|
90
94
|
runner.use(
|
|
91
95
|
async (context, next) => {
|
|
92
|
-
const { tx, itx, statedb, senderState } = context;
|
|
96
|
+
const { tx, itx, statedb, senderState, senderUpdates, vaultState, vaultUpdates } = context;
|
|
93
97
|
const data = decodeAnySafe(itx.data);
|
|
94
98
|
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
// We are definitely creating a different token, so it is safe to set tokens to initial supply
|
|
100
|
+
senderUpdates.tokens[itx.address] = itx.initialSupply;
|
|
97
101
|
|
|
98
|
-
const [newSenderState, tokenState] = await Promise.all([
|
|
102
|
+
const [newSenderState, tokenState, newVaultState] = await Promise.all([
|
|
99
103
|
statedb.account.update(
|
|
100
104
|
senderState.address,
|
|
101
|
-
account.update(senderState, {
|
|
105
|
+
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
102
106
|
context
|
|
103
107
|
),
|
|
108
|
+
|
|
104
109
|
statedb.token.create(itx.address, token.create({ ...itx, data, issuer: senderState.address }, context), context),
|
|
110
|
+
|
|
111
|
+
isEmpty(vaultUpdates)
|
|
112
|
+
? vaultState
|
|
113
|
+
: statedb.account.update(vaultState.address, account.update(vaultState, vaultUpdates, context), context),
|
|
105
114
|
]);
|
|
106
115
|
|
|
107
116
|
context.senderState = newSenderState;
|
|
108
117
|
context.tokenState = tokenState;
|
|
118
|
+
context.vaultState = newVaultState;
|
|
109
119
|
|
|
110
120
|
debug('create token v2', tokenState);
|
|
111
121
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable indent */
|
|
2
2
|
const Error = require('@ocap/util/lib/error');
|
|
3
|
+
const Joi = require('@ocap/validator');
|
|
3
4
|
const getListField = require('@ocap/util/lib/get-list-field');
|
|
4
5
|
const { BN, fromUnitToToken } = require('@ocap/util');
|
|
5
6
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
6
|
-
const { account, stake, evidence
|
|
7
|
+
const { account, stake, evidence } = require('@ocap/state');
|
|
7
8
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line global-require
|
|
@@ -11,14 +12,14 @@ const debug = require('debug')(`${require('../../../package.json').name}:deposit
|
|
|
11
12
|
|
|
12
13
|
const VerifySigners = require('../rollup/pipes/verify-signers');
|
|
13
14
|
const VerifyPaused = require('../rollup/pipes/verify-paused');
|
|
14
|
-
const { applyTokenUpdates, getTxFee, getRewardLocker } = require('../../util');
|
|
15
|
+
const { applyTokenUpdates, getTxFee, getBNSum, getRewardLocker } = require('../../util');
|
|
15
16
|
|
|
16
17
|
const schema = Joi.object({
|
|
17
|
-
token: Joi.
|
|
18
|
+
token: Joi.schemas.tokenInput.required(),
|
|
18
19
|
to: Joi.DID().wallet('ethereum').required(),
|
|
19
20
|
proposer: Joi.DID().wallet('ethereum').required(),
|
|
20
21
|
evidence: Joi.object({
|
|
21
|
-
hash: Joi.string().regex(Joi.
|
|
22
|
+
hash: Joi.string().regex(Joi.patterns.txHash).required(),
|
|
22
23
|
}).required(),
|
|
23
24
|
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
24
25
|
actualFee: Joi.BN().min(0).required(),
|
|
@@ -138,15 +139,15 @@ runner.use((context, next) => {
|
|
|
138
139
|
const { itx, rollupState, tokenState } = context;
|
|
139
140
|
const { depositFeeRate, maxDepositFee, minDepositFee } = rollupState;
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
const { reward } = getTxFee({
|
|
142
143
|
amount: itx.token.value,
|
|
143
144
|
feeRate: depositFeeRate,
|
|
144
145
|
maxFee: maxDepositFee,
|
|
145
146
|
minFee: minDepositFee,
|
|
146
147
|
});
|
|
147
148
|
|
|
148
|
-
if (new BN(itx.actualFee).lt(new BN(
|
|
149
|
-
const expected = fromUnitToToken(
|
|
149
|
+
if (new BN(itx.actualFee).lt(new BN(reward))) {
|
|
150
|
+
const expected = fromUnitToToken(reward, tokenState.decimal);
|
|
150
151
|
const actual = fromUnitToToken(itx.actualFee, tokenState.decimal);
|
|
151
152
|
return next(new Error('INVALID_TX', `itx.actualFee too low, expect at least ${expected}, got ${actual}`));
|
|
152
153
|
}
|
|
@@ -155,28 +156,33 @@ runner.use((context, next) => {
|
|
|
155
156
|
});
|
|
156
157
|
|
|
157
158
|
// 7. verify sender and signer states
|
|
158
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: '
|
|
159
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK', table: 'account' }));
|
|
159
160
|
runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
160
161
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
161
162
|
|
|
162
163
|
// 8. update state: the token minting is done when deposit finalized in rollup-block
|
|
163
164
|
runner.use(
|
|
164
165
|
async (context, next) => {
|
|
165
|
-
const { tx, itx,
|
|
166
|
+
const { tx, itx, statedb, senderState, stakeState, stakeAddress, lockerState, lockerAddress } = context;
|
|
166
167
|
|
|
167
|
-
const
|
|
168
|
-
const
|
|
168
|
+
const user = itx.token.value;
|
|
169
|
+
const fee = itx.actualFee;
|
|
170
|
+
const total = getBNSum(user, fee);
|
|
171
|
+
|
|
172
|
+
const stakeUpdates = applyTokenUpdates([{ address: itx.token.address, value: total }], stakeState, 'sub');
|
|
173
|
+
const senderUpdates = applyTokenUpdates([{ address: itx.token.address, value: user }], senderState || {}, 'add');
|
|
169
174
|
const lockerUpdates = applyTokenUpdates(
|
|
170
|
-
[{ address: itx.token.address, value:
|
|
175
|
+
[{ address: itx.token.address, value: fee }],
|
|
171
176
|
lockerState || { tokens: {} },
|
|
172
177
|
'add'
|
|
173
178
|
);
|
|
174
179
|
|
|
180
|
+
const sender = senderState ? senderState.address : tx.from;
|
|
175
181
|
const [newSenderState, newStakeState, newLockerState, evidenceState] = await Promise.all([
|
|
176
|
-
//
|
|
177
|
-
statedb.account.
|
|
178
|
-
senderState
|
|
179
|
-
account.
|
|
182
|
+
// updateOrCreate user account
|
|
183
|
+
statedb.account.updateOrCreate(
|
|
184
|
+
senderState,
|
|
185
|
+
account.updateOrCreate(senderState, { address: sender, nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
180
186
|
context
|
|
181
187
|
),
|
|
182
188
|
|
|
@@ -218,11 +224,11 @@ runner.use(
|
|
|
218
224
|
|
|
219
225
|
context.updatedAccounts = [
|
|
220
226
|
// stake for tx proposer is decreased
|
|
221
|
-
{ address: stakeAddress, token: itx.token.address, delta: `-${
|
|
227
|
+
{ address: stakeAddress, token: itx.token.address, delta: `-${total}`, action: 'unlock' },
|
|
222
228
|
// mint to depositor from stake
|
|
223
|
-
{ address:
|
|
224
|
-
//
|
|
225
|
-
{ address: lockerAddress, token: itx.token.address, delta:
|
|
229
|
+
{ address: sender, token: itx.token.address, delta: user, action: 'unlock' },
|
|
230
|
+
// tx fee is locked for later claiming
|
|
231
|
+
{ address: lockerAddress, token: itx.token.address, delta: fee, action: 'pending' },
|
|
226
232
|
];
|
|
227
233
|
|
|
228
234
|
debug('deposit-token-v2', itx);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable indent */
|
|
2
2
|
const Error = require('@ocap/util/lib/error');
|
|
3
|
+
const Joi = require('@ocap/validator');
|
|
3
4
|
const getListField = require('@ocap/util/lib/get-list-field');
|
|
4
5
|
const { BN, fromUnitToToken } = require('@ocap/util');
|
|
5
6
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
6
|
-
const { account, stake
|
|
7
|
+
const { account, stake } = require('@ocap/state');
|
|
7
8
|
const { toStakeAddress } = require('@arcblock/did-util');
|
|
8
9
|
|
|
9
10
|
// eslint-disable-next-line global-require
|
|
@@ -15,7 +16,7 @@ const { applyTokenUpdates, getTxFee, getBNSum, getRewardLocker } = require('../.
|
|
|
15
16
|
const verifyMultiSigV2 = pipes.VerifyMultiSigV2({ signersKey: 'signers' });
|
|
16
17
|
|
|
17
18
|
const schema = Joi.object({
|
|
18
|
-
token: Joi.
|
|
19
|
+
token: Joi.schemas.tokenInput.required(),
|
|
19
20
|
to: Joi.DID().wallet('ethereum').required(),
|
|
20
21
|
rollup: Joi.DID().role('ROLE_ROLLUP').required(),
|
|
21
22
|
proposer: Joi.DID().wallet('ethereum').optional().allow('').default(''),
|
|
@@ -99,15 +100,15 @@ runner.use((context, next) => {
|
|
|
99
100
|
|
|
100
101
|
const isFixedFee = new BN(itx.maxFee).isZero();
|
|
101
102
|
if (isFixedFee) {
|
|
102
|
-
|
|
103
|
+
const { reward } = getTxFee({
|
|
103
104
|
amount: itx.token.value,
|
|
104
105
|
feeRate: withdrawFeeRate,
|
|
105
106
|
maxFee: maxWithdrawFee,
|
|
106
107
|
minFee: minWithdrawFee,
|
|
107
108
|
});
|
|
108
109
|
|
|
109
|
-
if (new BN(itx.actualFee).lt(new BN(
|
|
110
|
-
const expected = fromUnitToToken(
|
|
110
|
+
if (new BN(itx.actualFee).lt(new BN(reward))) {
|
|
111
|
+
const expected = fromUnitToToken(reward, tokenState.decimal);
|
|
111
112
|
const actual = fromUnitToToken(itx.actualFee, tokenState.decimal);
|
|
112
113
|
return next(new Error('INVALID_TX', `itx.actualFee too low, expect at least ${expected}, got ${actual}`));
|
|
113
114
|
}
|
|
@@ -81,8 +81,8 @@ runner.use(pipes.VerifyListSize({ listKey: ['senderTokens', 'receiverTokens'] })
|
|
|
81
81
|
|
|
82
82
|
// TODO: anti-replay-exchange-attack
|
|
83
83
|
|
|
84
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
85
|
-
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK' }));
|
|
84
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
85
|
+
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
86
86
|
runner.use(pipes.VerifyDelegation({ type: 'signature', signerKey: 'senderState', delegatorKey: 'delegatorState' }));
|
|
87
87
|
runner.use(pipes.ExtractSigner({ signerKey: 'signerStates', delegatorKey: 'delegatorStates' }));
|
|
88
88
|
runner.use(
|
|
@@ -94,9 +94,9 @@ runner.use(
|
|
|
94
94
|
})
|
|
95
95
|
);
|
|
96
96
|
|
|
97
|
-
runner.use(pipes.ExtractState({ from: 'tokenAddress', to: 'tokenStates', status: 'INVALID_TOKEN' }));
|
|
97
|
+
runner.use(pipes.ExtractState({ from: 'tokenAddress', to: 'tokenStates', status: 'INVALID_TOKEN', table: 'token' }));
|
|
98
98
|
|
|
99
|
-
runner.use(pipes.ExtractState({ from: 'receiver', to: 'receiverState', status: 'INVALID_RECEIVER_STATE' }));
|
|
99
|
+
runner.use(pipes.ExtractState({ from: 'receiver', to: 'receiverState', status: 'INVALID_RECEIVER_STATE', table: 'account' })); // prettier-ignore
|
|
100
100
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState', signerKey: 'signerStates' }));
|
|
101
101
|
runner.use((context, next) => {
|
|
102
102
|
context.senderTokenConditions = {
|
|
@@ -114,11 +114,11 @@ runner.use(pipes.VerifyTokenBalance({ ownerKey: 'receiverState', conditionKey: '
|
|
|
114
114
|
|
|
115
115
|
runner.use(pipes.AntiLandAttack({ senderState: 'senderState', receiverState: 'receiverState' }));
|
|
116
116
|
|
|
117
|
-
runner.use(pipes.ExtractState({ from: 'senderAssets', to: 'priv.senderAssets', status: 'INVALID_ASSET' }));
|
|
117
|
+
runner.use(pipes.ExtractState({ from: 'senderAssets', to: 'priv.senderAssets', status: 'INVALID_ASSET', table: 'asset' })); // prettier-ignore
|
|
118
118
|
runner.use(pipes.VerifyTransferrable({ assets: 'priv.senderAssets' }));
|
|
119
119
|
runner.use(pipes.VerifyUpdater({ assetKey: 'priv.senderAssets', ownerKey: 'senderState' }));
|
|
120
120
|
|
|
121
|
-
runner.use(pipes.ExtractState({ from: 'receiverAssets', to: 'priv.receiverAssets', status: 'INVALID_ASSET' }));
|
|
121
|
+
runner.use(pipes.ExtractState({ from: 'receiverAssets', to: 'priv.receiverAssets', status: 'INVALID_ASSET', table: 'asset' })); // prettier-ignore
|
|
122
122
|
runner.use(pipes.VerifyTransferrable({ assets: 'priv.receiverAssets' }));
|
|
123
123
|
runner.use(pipes.VerifyUpdater({ assetKey: 'priv.receiverAssets', ownerKey: 'receiverState' }));
|
|
124
124
|
|
|
@@ -62,10 +62,10 @@ runner.use((context, next) => {
|
|
|
62
62
|
next();
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
65
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
66
66
|
runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
|
|
67
67
|
|
|
68
|
-
runner.use(pipes.ExtractState({ from: 'tokenAddress', to: 'tokenStates', status: 'INVALID_TOKEN' }));
|
|
68
|
+
runner.use(pipes.ExtractState({ from: 'tokenAddress', to: 'tokenStates', status: 'INVALID_TOKEN', table: 'token' }));
|
|
69
69
|
runner.use((context, next) => {
|
|
70
70
|
context.tokenConditions = {
|
|
71
71
|
owner: context.senderState.address,
|
|
@@ -75,24 +75,32 @@ runner.use((context, next) => {
|
|
|
75
75
|
});
|
|
76
76
|
runner.use(pipes.VerifyTokenBalance({ ownerKey: 'senderState', conditionKey: 'tokenConditions' }));
|
|
77
77
|
|
|
78
|
-
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK' }));
|
|
78
|
+
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
79
79
|
runner.use(pipes.VerifyDelegation({ type: 'signature', signerKey: 'senderState', delegatorKey: 'delegatorState' }));
|
|
80
80
|
|
|
81
|
-
runner.use(pipes.ExtractReceiver({ from: 'itx.to' }));
|
|
82
|
-
runner.use(pipes.ExtractState({ from: 'receiver', to: 'receiverState', status: '
|
|
81
|
+
runner.use(pipes.ExtractReceiver({ from: 'itx.to', to: 'receiver' }));
|
|
82
|
+
runner.use(pipes.ExtractState({ from: 'receiver', to: 'receiverState', status: 'OK', table: 'account' }));
|
|
83
83
|
runner.use(pipes.AntiLandAttack({ senderState: 'senderState', receiverState: 'receiverState' }));
|
|
84
84
|
|
|
85
|
-
runner.use(pipes.ExtractState({ from: 'assets', to: 'assetStates', status: 'INVALID_ASSET' }));
|
|
85
|
+
runner.use(pipes.ExtractState({ from: 'assets', to: 'assetStates', status: 'INVALID_ASSET', table: 'asset' }));
|
|
86
86
|
runner.use(pipes.VerifyTransferrable({ assets: 'assetStates' }));
|
|
87
87
|
runner.use(pipes.VerifyUpdater({ assetKey: 'assetStates', ownerKey: 'senderState' }));
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
// transfer assets to new owner
|
|
90
|
+
runner.use((context, next) => {
|
|
91
|
+
const { itx, receiverState } = context;
|
|
92
|
+
context.receiverAddr = receiverState ? receiverState.address : itx.to;
|
|
93
|
+
return next();
|
|
94
|
+
});
|
|
95
|
+
runner.use(pipes.UpdateOwner({ assets: 'assetStates', owner: 'receiverAddr' }));
|
|
96
|
+
|
|
97
|
+
// update statedb: transfer tokens to new owner
|
|
90
98
|
runner.use(
|
|
91
99
|
async (context, next) => {
|
|
92
|
-
const { tx, itx, tokens, senderState, receiverState, statedb } = context;
|
|
100
|
+
const { tx, itx, tokens, senderState, receiverAddr, receiverState, statedb } = context;
|
|
93
101
|
|
|
94
102
|
const { tokens: senderTokens = {} } = senderState;
|
|
95
|
-
const { tokens: receiverTokens = {} } = receiverState;
|
|
103
|
+
const { tokens: receiverTokens = {} } = receiverState || {};
|
|
96
104
|
for (const token of tokens) {
|
|
97
105
|
const delta = new BN(token.value);
|
|
98
106
|
senderTokens[token.address] = new BN(senderTokens[token.address]).sub(delta).toString();
|
|
@@ -103,14 +111,14 @@ runner.use(
|
|
|
103
111
|
// Update sender state
|
|
104
112
|
statedb.account.update(
|
|
105
113
|
senderState.address,
|
|
106
|
-
account.update(senderState, { nonce: tx.nonce, tokens: senderTokens }, context),
|
|
114
|
+
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, tokens: senderTokens }, context),
|
|
107
115
|
context
|
|
108
116
|
),
|
|
109
117
|
|
|
110
118
|
// Update receiver state
|
|
111
|
-
statedb.account.
|
|
112
|
-
receiverState
|
|
113
|
-
account.
|
|
119
|
+
statedb.account.updateOrCreate(
|
|
120
|
+
receiverState,
|
|
121
|
+
account.updateOrCreate(receiverState, { address: receiverAddr, tokens: receiverTokens }, context),
|
|
114
122
|
context
|
|
115
123
|
),
|
|
116
124
|
]);
|
|
@@ -108,9 +108,9 @@ runner.use(
|
|
|
108
108
|
runner.use(pipes.VerifyMultiSigV2({ signersKey: 'senders' }));
|
|
109
109
|
|
|
110
110
|
// 4. verify sender & signer & receiver
|
|
111
|
-
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
|
|
112
|
-
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE' }));
|
|
113
|
-
runner.use(pipes.ExtractState({ from: 'receivers', to: 'receiverStates', status: '
|
|
111
|
+
runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
|
|
112
|
+
runner.use(pipes.ExtractState({ from: 'senders', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
|
|
113
|
+
runner.use(pipes.ExtractState({ from: 'receivers', to: 'receiverStates', status: 'OK', table: 'account' }));
|
|
114
114
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
|
|
115
115
|
|
|
116
116
|
// 5. verify token state and balance
|
|
@@ -140,7 +140,17 @@ runner.use(async (context, next) => {
|
|
|
140
140
|
|
|
141
141
|
runner.use(
|
|
142
142
|
async (context, next) => {
|
|
143
|
-
const {
|
|
143
|
+
const {
|
|
144
|
+
tx,
|
|
145
|
+
inputs,
|
|
146
|
+
outputs,
|
|
147
|
+
receivers,
|
|
148
|
+
senderState,
|
|
149
|
+
signerStates,
|
|
150
|
+
receiverStates = [],
|
|
151
|
+
assetStates = [],
|
|
152
|
+
statedb,
|
|
153
|
+
} = context;
|
|
144
154
|
|
|
145
155
|
const signerUpdates = {};
|
|
146
156
|
inputs.forEach((x) => {
|
|
@@ -157,7 +167,7 @@ runner.use(
|
|
|
157
167
|
const { owner, tokensList } = x;
|
|
158
168
|
receiverUpdates[owner] = applyTokenUpdates(
|
|
159
169
|
tokensList,
|
|
160
|
-
receiverStates.find((s) => s.address === owner),
|
|
170
|
+
receiverStates.find((s) => s.address === owner) || {},
|
|
161
171
|
'add'
|
|
162
172
|
);
|
|
163
173
|
});
|
|
@@ -175,7 +185,6 @@ runner.use(
|
|
|
175
185
|
|
|
176
186
|
debug('transfer-v3', { signerUpdates, receiverUpdates, assetUpdates, isAlsoSigner, isAlsoReceiver });
|
|
177
187
|
|
|
178
|
-
// FIXME: skip statedb update if account not changed at all
|
|
179
188
|
const [newSenderState, newSignerStates, newReceiverStates, newAssetStates] = await Promise.all([
|
|
180
189
|
// Update sender state
|
|
181
190
|
statedb.account.update(
|
|
@@ -183,7 +192,7 @@ runner.use(
|
|
|
183
192
|
account.update(
|
|
184
193
|
senderState,
|
|
185
194
|
Object.assign(
|
|
186
|
-
{ nonce: tx.nonce },
|
|
195
|
+
{ nonce: tx.nonce, pk: tx.pk },
|
|
187
196
|
signerUpdates[senderState.address] || {},
|
|
188
197
|
receiverUpdates[senderState.address] || {}
|
|
189
198
|
),
|
|
@@ -199,13 +208,18 @@ runner.use(
|
|
|
199
208
|
.map((x) => statedb.account.update(x.address, account.update(x, signerUpdates[x.address], context), context))
|
|
200
209
|
),
|
|
201
210
|
|
|
202
|
-
//
|
|
211
|
+
// UpdateOrCreate receiver state
|
|
203
212
|
Promise.all(
|
|
204
|
-
|
|
205
|
-
.filter((x) => x
|
|
206
|
-
.map((x) =>
|
|
207
|
-
|
|
208
|
-
|
|
213
|
+
receivers
|
|
214
|
+
.filter((x) => x !== senderState.address)
|
|
215
|
+
.map((x) => {
|
|
216
|
+
const receiverState = receiverStates.find((s) => s.address === x);
|
|
217
|
+
return statedb.account.updateOrCreate(
|
|
218
|
+
receiverState,
|
|
219
|
+
account.updateOrCreate(receiverState, { ...receiverUpdates[x], address: x }, context),
|
|
220
|
+
context
|
|
221
|
+
);
|
|
222
|
+
})
|
|
209
223
|
),
|
|
210
224
|
|
|
211
225
|
// Update asset state
|
package/lib/util.js
CHANGED
|
@@ -165,7 +165,7 @@ const splitTxFee = ({ total, shares = {}, stringify = true }) => {
|
|
|
165
165
|
|
|
166
166
|
const getRewardLocker = (rollupAddress) => toStakeAddress(rollupAddress, rollupAddress);
|
|
167
167
|
const getBNSum = (...args) => flattenDeep(args).reduce((sum, x) => sum.add(new BN(x)), new BN(0)).toString(10); // prettier-ignore
|
|
168
|
-
const isFixedFee = (x) => new BN(x.tx.itxJson.maxFee).isZero();
|
|
168
|
+
const isFixedFee = (x) => !x.tx.itxJson.maxFee || new BN(x.tx.itxJson.maxFee).isZero();
|
|
169
169
|
|
|
170
170
|
const ensureBlockReward = (rollupState, minReward, txStates) => {
|
|
171
171
|
const { address, withdrawFeeRate, minWithdrawFee, maxWithdrawFee, tokenAddress } = rollupState;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.13.
|
|
6
|
+
"version": "1.13.66",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -19,16 +19,17 @@
|
|
|
19
19
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@arcblock/did": "1.13.
|
|
23
|
-
"@arcblock/did-util": "1.13.
|
|
24
|
-
"@ocap/asset": "1.13.
|
|
25
|
-
"@ocap/mcrypto": "1.13.
|
|
26
|
-
"@ocap/merkle-tree": "1.13.
|
|
27
|
-
"@ocap/message": "1.13.
|
|
28
|
-
"@ocap/state": "1.13.
|
|
29
|
-
"@ocap/tx-pipeline": "1.13.
|
|
30
|
-
"@ocap/util": "1.13.
|
|
31
|
-
"@ocap/
|
|
22
|
+
"@arcblock/did": "1.13.66",
|
|
23
|
+
"@arcblock/did-util": "1.13.66",
|
|
24
|
+
"@ocap/asset": "1.13.66",
|
|
25
|
+
"@ocap/mcrypto": "1.13.66",
|
|
26
|
+
"@ocap/merkle-tree": "1.13.66",
|
|
27
|
+
"@ocap/message": "1.13.66",
|
|
28
|
+
"@ocap/state": "1.13.66",
|
|
29
|
+
"@ocap/tx-pipeline": "1.13.66",
|
|
30
|
+
"@ocap/util": "1.13.66",
|
|
31
|
+
"@ocap/validator": "1.13.66",
|
|
32
|
+
"@ocap/wallet": "1.13.66",
|
|
32
33
|
"debug": "^4.3.2",
|
|
33
34
|
"empty-value": "^1.0.1",
|
|
34
35
|
"lodash": "^4.17.21",
|
|
@@ -41,5 +42,5 @@
|
|
|
41
42
|
"devDependencies": {
|
|
42
43
|
"jest": "^27.3.1"
|
|
43
44
|
},
|
|
44
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "1395a8dccee398dd0aed47c2b54a2c6e350d8621"
|
|
45
46
|
}
|