@ocap/tx-protocols 1.18.95 → 1.18.97
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/delegate.js +77 -24
- package/lib/protocols/account/revoke-delegate.js +0 -1
- package/lib/protocols/asset/acquire-v2.js +19 -5
- package/lib/protocols/asset/create.js +21 -7
- package/lib/protocols/asset/pipes/verify-itx-assets.js +1 -1
- package/lib/protocols/factory/create.js +29 -6
- package/lib/protocols/rollup/create.js +29 -6
- package/lib/protocols/token/create.js +19 -6
- package/lib/protocols/trade/exchange-v2.js +3 -1
- package/lib/protocols/trade/transfer-v2.js +32 -5
- package/lib/util.js +17 -0
- package/package.json +14 -14
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/* eslint-disable max-len */
|
|
2
2
|
const get = require('lodash/get');
|
|
3
|
+
const cloneDeep = require('lodash/cloneDeep');
|
|
4
|
+
const pick = require('lodash/pick');
|
|
3
5
|
const { Joi } = require('@arcblock/validator');
|
|
4
6
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
5
|
-
const { getListField } = require('@ocap/util/lib/get-list-field');
|
|
6
7
|
const { delegation, account } = require('@ocap/state');
|
|
7
8
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
8
9
|
const { toDelegateAddress } = require('@arcblock/did-util');
|
|
10
|
+
const { formatMessage } = require('@ocap/message');
|
|
9
11
|
|
|
10
12
|
// eslint-disable-next-line global-require
|
|
11
13
|
const debug = require('debug')(`${require('../../../package.json').name}:delegate`);
|
|
@@ -17,6 +19,29 @@ const runner = new Runner();
|
|
|
17
19
|
|
|
18
20
|
runner.use(pipes.VerifyMultiSig(0));
|
|
19
21
|
|
|
22
|
+
const rateLimit = Joi.object({
|
|
23
|
+
interval: Joi.number().integer().greater(0).required(),
|
|
24
|
+
anchor: Joi.number().integer().min(0).optional().default(0),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const tokenLimit = Joi.object({
|
|
28
|
+
address: Joi.DID().role('ROLE_TOKEN').required(),
|
|
29
|
+
toList: Joi.array().items(Joi.DID()).max(32).unique().optional().default([]),
|
|
30
|
+
txCount: Joi.number().integer().min(0).empty('').optional().default(0),
|
|
31
|
+
txAllowance: Joi.BN().optional().default('0'),
|
|
32
|
+
totalAllowance: Joi.BN().optional().default('0'),
|
|
33
|
+
validUntil: Joi.number().integer().min(0).empty('').optional().default(0),
|
|
34
|
+
rate: rateLimit.optional(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const assetLimit = Joi.object({
|
|
38
|
+
address: Joi.array().items(Joi.DID().role('ROLE_ASSET')).unique().max(1024).optional().default([]),
|
|
39
|
+
toList: Joi.array().items(Joi.DID()).unique().max(32).optional().default([]),
|
|
40
|
+
txCount: Joi.number().integer().min(0).empty('').optional().default(0),
|
|
41
|
+
validUntil: Joi.number().integer().min(0).empty('').optional().default(0),
|
|
42
|
+
rate: rateLimit.optional(),
|
|
43
|
+
});
|
|
44
|
+
|
|
20
45
|
// verify itx
|
|
21
46
|
const schema = Joi.object({
|
|
22
47
|
address: Joi.DID().prefix().role('ROLE_DELEGATION').required(),
|
|
@@ -25,28 +50,33 @@ const schema = Joi.object({
|
|
|
25
50
|
.items(
|
|
26
51
|
Joi.object({
|
|
27
52
|
typeUrl: Joi.string().required(),
|
|
53
|
+
limit: Joi.object({
|
|
54
|
+
tokensList: Joi.array()
|
|
55
|
+
.items(tokenLimit)
|
|
56
|
+
.unique((a, b) => a.address === b.address)
|
|
57
|
+
.max(32),
|
|
58
|
+
assetsList: Joi.array().items(assetLimit).max(32),
|
|
59
|
+
})
|
|
60
|
+
.optional()
|
|
61
|
+
.default({ tokensList: [], assetsList: [] }),
|
|
28
62
|
})
|
|
29
63
|
)
|
|
64
|
+
.unique((a, b) => a.typeUrl === b.typeUrl)
|
|
30
65
|
.min(1)
|
|
31
66
|
.required(),
|
|
32
67
|
data: Joi.any().optional(),
|
|
33
68
|
}).options({ stripUnknown: true, noDefaults: false });
|
|
34
|
-
runner.use((
|
|
35
|
-
const { error } = schema.validate(itx);
|
|
69
|
+
runner.use((context, next) => {
|
|
70
|
+
const { error, value } = schema.validate(context.itx);
|
|
36
71
|
if (error) {
|
|
37
72
|
return next(new Error('INVALID_TX', `Invalid itx: ${error.message}`));
|
|
38
73
|
}
|
|
74
|
+
context.formattedItx = formatMessage('DelegateTx', context.itx);
|
|
75
|
+
context.validatedItx = value;
|
|
39
76
|
return next();
|
|
40
77
|
});
|
|
41
78
|
runner.use(
|
|
42
79
|
pipes.VerifyInfo([
|
|
43
|
-
{
|
|
44
|
-
error: 'OK',
|
|
45
|
-
fn: (context) => {
|
|
46
|
-
context.ops = getListField(context, 'itx.ops');
|
|
47
|
-
return true;
|
|
48
|
-
},
|
|
49
|
-
},
|
|
50
80
|
{
|
|
51
81
|
error: 'INVALID_TX',
|
|
52
82
|
message: 'Delegation address does not match',
|
|
@@ -55,10 +85,9 @@ runner.use(
|
|
|
55
85
|
{
|
|
56
86
|
error: 'INVALID_DELEGATION_TYPE_URL',
|
|
57
87
|
message: 'Delegation type url is not allowed',
|
|
58
|
-
fn: ({
|
|
88
|
+
fn: ({ formattedItx, config }) => {
|
|
59
89
|
const allowed = get(config, 'transaction.delegate.typeUrls', []);
|
|
60
|
-
|
|
61
|
-
return ops.every((op) => allowed.includes(op.typeUrl));
|
|
90
|
+
return formattedItx.ops.every((op) => allowed.includes(op.typeUrl));
|
|
62
91
|
},
|
|
63
92
|
},
|
|
64
93
|
])
|
|
@@ -98,15 +127,40 @@ runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
|
98
127
|
// Create delegation state
|
|
99
128
|
runner.use(
|
|
100
129
|
async (context, next) => {
|
|
101
|
-
const {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
const {
|
|
131
|
+
tx,
|
|
132
|
+
itx,
|
|
133
|
+
formattedItx,
|
|
134
|
+
validatedItx,
|
|
135
|
+
statedb,
|
|
136
|
+
senderState,
|
|
137
|
+
receiverState,
|
|
138
|
+
delegationState,
|
|
139
|
+
senderUpdates,
|
|
140
|
+
updateVaults,
|
|
141
|
+
} = context;
|
|
142
|
+
|
|
143
|
+
const merged = cloneDeep(formattedItx.ops).reduce(
|
|
144
|
+
(acc, x, i) => {
|
|
105
145
|
acc[x.typeUrl] = {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
146
|
+
// This performs a reset of the limit
|
|
147
|
+
limit: {
|
|
148
|
+
tokens: (x.limit?.tokens || []).map((y, j) => {
|
|
149
|
+
const input = validatedItx.opsList[i].limit.tokensList[j];
|
|
150
|
+
return Object.assign(y, pick(input, ['txCount', 'txAllowance', 'totalAllowance', 'validUntil', 'rate']), {
|
|
151
|
+
txSent: 0,
|
|
152
|
+
lastTx: y.rate ? y.rate.anchor : 0,
|
|
153
|
+
spentAllowance: '0',
|
|
154
|
+
});
|
|
155
|
+
}),
|
|
156
|
+
assets: (x.limit?.assets || []).map((y, j) => {
|
|
157
|
+
const input = validatedItx.opsList[i].limit.assetsList[j];
|
|
158
|
+
return Object.assign(y, pick(input, ['txCount', 'validUntil', 'rate']), {
|
|
159
|
+
txSent: 0,
|
|
160
|
+
lastTx: y.rate ? y.rate.anchor : 0,
|
|
161
|
+
});
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
110
164
|
};
|
|
111
165
|
return acc;
|
|
112
166
|
},
|
|
@@ -129,10 +183,9 @@ runner.use(
|
|
|
129
183
|
? Promise.resolve(receiverState)
|
|
130
184
|
: statedb.account.create(receiver, account.create({ address: receiver }, context), context),
|
|
131
185
|
|
|
132
|
-
// update delegation
|
|
133
186
|
delegationState
|
|
134
|
-
? statedb.delegation.update(itx.address, delegation.update(delegationState, { ...itx, ops:
|
|
135
|
-
: statedb.delegation.create(itx.address, delegation.create({ ...itx, ops:
|
|
187
|
+
? statedb.delegation.update(itx.address, delegation.update(delegationState, { ...itx, ops: merged }, context), context) // prettier-ignore
|
|
188
|
+
: statedb.delegation.create(itx.address, delegation.create({ ...itx, from: tx.from, ops: merged }, context), context), // prettier-ignore
|
|
136
189
|
|
|
137
190
|
updateVaults(),
|
|
138
191
|
]);
|
|
@@ -50,7 +50,6 @@ runner.use(
|
|
|
50
50
|
message: 'Delegation type url is not allowed',
|
|
51
51
|
fn: ({ typeUrls, config }) => {
|
|
52
52
|
const allowed = get(config, 'transaction.delegate.typeUrls', []);
|
|
53
|
-
// TODO: support rule simulating and checking here
|
|
54
53
|
return typeUrls.every((x) => allowed.includes(x));
|
|
55
54
|
},
|
|
56
55
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable function-paren-newline */
|
|
2
2
|
const { promisify } = require('util');
|
|
3
3
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
4
|
-
const { account, asset, factory } = require('@ocap/state');
|
|
4
|
+
const { account, asset, factory, delegation } = require('@ocap/state');
|
|
5
5
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
6
6
|
const { Joi, schemas } = require('@arcblock/validator');
|
|
7
7
|
|
|
@@ -61,9 +61,16 @@ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INV
|
|
|
61
61
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'senderState', addressKey: 'tx.from' }));
|
|
62
62
|
|
|
63
63
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK' }));
|
|
64
|
-
runner.use(pipes.VerifyDelegation({ type: 'signature', signerKey: 'senderState', delegatorKey: 'delegatorState' }));
|
|
65
|
-
|
|
66
64
|
runner.use(pipes.ExtractState({ from: 'itx.factory', to: 'factoryState', status: 'INVALID_FACTORY_STATE', table: 'factory' })); // prettier-ignore
|
|
65
|
+
runner.use(
|
|
66
|
+
pipes.VerifyDelegation({
|
|
67
|
+
type: 'signature',
|
|
68
|
+
signerKey: 'senderState',
|
|
69
|
+
delegatorKey: 'delegatorState',
|
|
70
|
+
getRequirements: (context) => context.factoryState.input.tokens.map((x) => ({ type: 'token', ...x })),
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
|
|
67
74
|
runner.use(pipes.ExtractState({ from: 'factoryState.owner', to: 'factoryOwnerState', status: 'INVALID_OWNER_STATE' , table: 'account'})); // prettier-ignore
|
|
68
75
|
runner.use(pipes.ExtractState({ from: 'factoryState.trustedIssuers', to: 'issuerStates', status: 'INVALID_ISSUER_STATE' , table: 'account'})); // prettier-ignore
|
|
69
76
|
runner.use(pipes.ExtractState({ from: 'itx.issuer.id', to: 'issuerState', status: 'INVALID_ISSUER_STATE', table: 'account' })); // prettier-ignore
|
|
@@ -124,7 +131,7 @@ runner.use(verifyItxAssets);
|
|
|
124
131
|
runner.use(
|
|
125
132
|
EnsureTxGas((context) => {
|
|
126
133
|
// FIXME: payment check
|
|
127
|
-
const result = { create: 1, update:
|
|
134
|
+
const result = { create: 1, update: 3, payment: 0 };
|
|
128
135
|
if (context.assetStates) {
|
|
129
136
|
result.update += context.assetStates.length;
|
|
130
137
|
}
|
|
@@ -148,6 +155,7 @@ runner.use(
|
|
|
148
155
|
assetOwner,
|
|
149
156
|
factoryState,
|
|
150
157
|
factoryTokens,
|
|
158
|
+
delegationState,
|
|
151
159
|
mintedAsset,
|
|
152
160
|
mintedAddress,
|
|
153
161
|
senderChange,
|
|
@@ -177,7 +185,7 @@ runner.use(
|
|
|
177
185
|
context.tokenUpdates = applyTokenUpdates(factoryTokens, { tokens: {} }, 'add');
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
const [newSenderState, assetState, newFactoryState, newAssetStates] = await Promise.all([
|
|
188
|
+
const [newSenderState, assetState, newFactoryState, newAssetStates, newDelegationState] = await Promise.all([
|
|
181
189
|
// Update sender state
|
|
182
190
|
statedb.account.update(senderState.address, account.update(senderState, senderUpdates, context), context),
|
|
183
191
|
|
|
@@ -198,6 +206,11 @@ runner.use(
|
|
|
198
206
|
)
|
|
199
207
|
),
|
|
200
208
|
|
|
209
|
+
// Update delegation state
|
|
210
|
+
context.isDelegationChanged
|
|
211
|
+
? statedb.delegation.update(delegationState.address, delegation.update(delegationState, {}, context), context)
|
|
212
|
+
: delegationState,
|
|
213
|
+
|
|
201
214
|
// Update delegator state
|
|
202
215
|
context.delegatorState
|
|
203
216
|
? statedb.account.update(assetOwner.address, account.update(assetOwner, ownerUpdates, context), context)
|
|
@@ -210,6 +223,7 @@ runner.use(
|
|
|
210
223
|
context.assetState = assetState;
|
|
211
224
|
context.factoryState = newFactoryState;
|
|
212
225
|
context.assetStates = newAssetStates;
|
|
226
|
+
context.delegationState = newDelegationState;
|
|
213
227
|
|
|
214
228
|
debug('acquire-v2', assetState);
|
|
215
229
|
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
3
3
|
const cloneDeep = require('lodash/cloneDeep');
|
|
4
4
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
5
|
-
const { account, asset } = require('@ocap/state');
|
|
5
|
+
const { account, asset, delegation } = require('@ocap/state');
|
|
6
6
|
const { formatMessage } = require('@ocap/message');
|
|
7
7
|
const { toAssetAddress } = require('@arcblock/did-util');
|
|
8
8
|
|
|
9
9
|
// eslint-disable-next-line global-require
|
|
10
10
|
const debug = require('debug')(`${require('../../../package.json').name}:create-asset`);
|
|
11
11
|
|
|
12
|
-
const { decodeAnySafe } = require('../../util');
|
|
12
|
+
const { decodeAnySafe, getDelegationRequirements } = require('../../util');
|
|
13
13
|
|
|
14
14
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
15
15
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
@@ -71,14 +71,21 @@ runner.use(pipes.VerifyAccountMigration({ stateKey: 'senderState', addressKey: '
|
|
|
71
71
|
// Ensure delegation
|
|
72
72
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
73
73
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'delegatorState', addressKey: 'tx.delegator' }));
|
|
74
|
-
runner.use(
|
|
74
|
+
runner.use(
|
|
75
|
+
pipes.VerifyDelegation({
|
|
76
|
+
type: 'signature',
|
|
77
|
+
signerKey: 'senderState',
|
|
78
|
+
delegatorKey: 'delegatorState',
|
|
79
|
+
getRequirements: getDelegationRequirements,
|
|
80
|
+
})
|
|
81
|
+
);
|
|
75
82
|
|
|
76
83
|
// Check if parent is a factory
|
|
77
84
|
runner.use(pipes.ExtractState({ from: 'itx.parent', to: 'factoryState', status: 'OK', table: 'factory' }));
|
|
78
85
|
runner.use(
|
|
79
86
|
pipes.VerifyInfo([
|
|
80
87
|
// For security consideration, user can not create fake assets from a factory
|
|
81
|
-
// https://github.com/ArcBlock/
|
|
88
|
+
// https://github.com/ArcBlock/blockchain/issues/97
|
|
82
89
|
{
|
|
83
90
|
error: 'CREATE_FROM_FACTORY',
|
|
84
91
|
message: 'You can only get asset from factory from acquire or mint',
|
|
@@ -92,16 +99,17 @@ runner.use(
|
|
|
92
99
|
runner.use(pipes.ExtractState({ from: 'itx.parent', to: 'parentAsset', status: 'INVALID_ASSET', table: 'asset' }));
|
|
93
100
|
|
|
94
101
|
// Ensure tx fee and gas
|
|
95
|
-
runner.use(EnsureTxGas(() => ({ create: 1, update:
|
|
102
|
+
runner.use(EnsureTxGas(() => ({ create: 1, update: 2, payment: 0 })));
|
|
96
103
|
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
97
104
|
|
|
98
105
|
// Update asset state
|
|
99
106
|
runner.use(
|
|
100
107
|
async (context, next) => {
|
|
101
|
-
const { tx, itx, assetData, statedb, senderState, delegatorState, senderUpdates, updateVaults } =
|
|
108
|
+
const { tx, itx, assetData, statedb, senderState, delegatorState, delegationState, senderUpdates, updateVaults } =
|
|
109
|
+
context;
|
|
102
110
|
const owner = delegatorState ? delegatorState.address : senderState.address;
|
|
103
111
|
|
|
104
|
-
const [newSenderState, assetState] = await Promise.all([
|
|
112
|
+
const [newSenderState, assetState, newDelegationState] = await Promise.all([
|
|
105
113
|
statedb.account.update(
|
|
106
114
|
senderState.address,
|
|
107
115
|
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
@@ -115,10 +123,16 @@ runner.use(
|
|
|
115
123
|
),
|
|
116
124
|
|
|
117
125
|
updateVaults(),
|
|
126
|
+
|
|
127
|
+
// Update delegation state
|
|
128
|
+
context.isDelegationChanged
|
|
129
|
+
? statedb.delegation.update(delegationState.address, delegation.update(delegationState, {}, context), context)
|
|
130
|
+
: delegationState,
|
|
118
131
|
]);
|
|
119
132
|
|
|
120
133
|
context.senderState = newSenderState;
|
|
121
134
|
context.assetState = assetState;
|
|
135
|
+
context.delegationState = newDelegationState;
|
|
122
136
|
|
|
123
137
|
debug('createAsset', assetState);
|
|
124
138
|
|
|
@@ -16,7 +16,7 @@ module.exports = (context, next) => {
|
|
|
16
16
|
return next(new Error('INVALID_ASSET', 'Input asset does not exist on chain'));
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
// https://github.com/ArcBlock/
|
|
19
|
+
// https://github.com/ArcBlock/blockchain/issues/96
|
|
20
20
|
// If factory.input.assets are all factory
|
|
21
21
|
if (expectedFactoryStates.length === expectedAssets.length) {
|
|
22
22
|
// Just ensure that input assets are minted from any of the factory
|
|
@@ -7,13 +7,13 @@ const { isValidFactory } = require('@ocap/asset');
|
|
|
7
7
|
const { formatMessage } = require('@ocap/message');
|
|
8
8
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
9
9
|
const { BN } = require('@ocap/util');
|
|
10
|
-
const { account, factory } = require('@ocap/state');
|
|
10
|
+
const { account, factory, delegation } = require('@ocap/state');
|
|
11
11
|
const { toFactoryAddress } = require('@arcblock/did-util');
|
|
12
12
|
|
|
13
13
|
// eslint-disable-next-line global-require
|
|
14
14
|
const debug = require('debug')(`${require('../../../package.json').name}:create-factory`);
|
|
15
15
|
|
|
16
|
-
const { decodeAnySafe } = require('../../util');
|
|
16
|
+
const { decodeAnySafe, getDelegationRequirements } = require('../../util');
|
|
17
17
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
18
18
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
19
19
|
|
|
@@ -87,7 +87,14 @@ runner.use(pipes.VerifyAccountMigration({ stateKey: 'senderState', addressKey: '
|
|
|
87
87
|
// Ensure delegation
|
|
88
88
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
89
89
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'delegatorState', addressKey: 'tx.delegator' }));
|
|
90
|
-
runner.use(
|
|
90
|
+
runner.use(
|
|
91
|
+
pipes.VerifyDelegation({
|
|
92
|
+
type: 'signature',
|
|
93
|
+
signerKey: 'senderState',
|
|
94
|
+
delegatorKey: 'delegatorState',
|
|
95
|
+
getRequirements: getDelegationRequirements,
|
|
96
|
+
})
|
|
97
|
+
);
|
|
91
98
|
|
|
92
99
|
// Ensure tokens exist if we are creating an factory that consume tokens
|
|
93
100
|
runner.use(pipes.ExtractState({ from: 'factoryTokens', to: 'tokenStates', table: 'token', status: 'INVALID_FACTORY_INPUT' })); // prettier-ignore
|
|
@@ -113,17 +120,27 @@ runner.use(pipes.ExtractState({ from: 'factoryProps.trustedIssuers', to: 'issuer
|
|
|
113
120
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'issuerStates', addressKey: 'factoryProps.trustedIssuers' }));
|
|
114
121
|
|
|
115
122
|
// Ensure tx fee and gas
|
|
116
|
-
runner.use(EnsureTxGas(() => ({ create: 1, update:
|
|
123
|
+
runner.use(EnsureTxGas(() => ({ create: 1, update: 2, payment: 0 })));
|
|
117
124
|
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
118
125
|
|
|
119
126
|
// Create factory state
|
|
120
127
|
runner.use(
|
|
121
128
|
async (context, next) => {
|
|
122
|
-
const {
|
|
129
|
+
const {
|
|
130
|
+
tx,
|
|
131
|
+
itx,
|
|
132
|
+
statedb,
|
|
133
|
+
senderState,
|
|
134
|
+
delegatorState,
|
|
135
|
+
delegationState,
|
|
136
|
+
senderUpdates,
|
|
137
|
+
factoryProps,
|
|
138
|
+
updateVaults,
|
|
139
|
+
} = context;
|
|
123
140
|
const tokens = { [context.config.token.address]: '0' };
|
|
124
141
|
const owner = delegatorState ? delegatorState.address : senderState.address;
|
|
125
142
|
|
|
126
|
-
const [newSenderState, factoryState] = await Promise.all([
|
|
143
|
+
const [newSenderState, factoryState, newDelegationState] = await Promise.all([
|
|
127
144
|
// Update owner state
|
|
128
145
|
statedb.account.update(
|
|
129
146
|
senderState.address,
|
|
@@ -134,11 +151,17 @@ runner.use(
|
|
|
134
151
|
// Create factory state
|
|
135
152
|
statedb.factory.create(itx.address, factory.create({ ...factoryProps, tokens, owner }, context), context),
|
|
136
153
|
|
|
154
|
+
// Update delegation state
|
|
155
|
+
context.isDelegationChanged
|
|
156
|
+
? statedb.delegation.update(delegationState.address, delegation.update(delegationState, {}, context), context)
|
|
157
|
+
: delegationState,
|
|
158
|
+
|
|
137
159
|
updateVaults(),
|
|
138
160
|
]);
|
|
139
161
|
|
|
140
162
|
context.senderState = newSenderState;
|
|
141
163
|
context.factoryState = factoryState;
|
|
164
|
+
context.delegationState = newDelegationState;
|
|
142
165
|
|
|
143
166
|
debug('createFactory', factoryState);
|
|
144
167
|
|
|
@@ -3,7 +3,7 @@ const isEmpty = require('empty-value');
|
|
|
3
3
|
const cloneDeep = require('lodash/cloneDeep');
|
|
4
4
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
5
5
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
6
|
-
const { account, rollup } = require('@ocap/state');
|
|
6
|
+
const { account, rollup, delegation } = require('@ocap/state');
|
|
7
7
|
const { formatMessage } = require('@ocap/message');
|
|
8
8
|
const { isFromPublicKey, isEthereumDid } = require('@arcblock/did');
|
|
9
9
|
const { toRollupAddress } = require('@arcblock/did-util');
|
|
@@ -11,7 +11,7 @@ const { toRollupAddress } = require('@arcblock/did-util');
|
|
|
11
11
|
// eslint-disable-next-line global-require
|
|
12
12
|
const debug = require('debug')(`${require('../../../package.json').name}:create-rollup`);
|
|
13
13
|
|
|
14
|
-
const { decodeAnySafe } = require('../../util');
|
|
14
|
+
const { decodeAnySafe, getDelegationRequirements } = require('../../util');
|
|
15
15
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
16
16
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
17
17
|
|
|
@@ -73,7 +73,14 @@ runner.use(pipes.ExtractState({ from: 'seedValidators', to: 'validatorStates', s
|
|
|
73
73
|
runner.use(pipes.VerifyAccountMigration({ signerKey: 'validatorStates', stateKey: 'senderState', addressKey: 'tx.from' })); // prettier-ignore
|
|
74
74
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
75
75
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'delegatorState', addressKey: 'tx.delegator' }));
|
|
76
|
-
runner.use(
|
|
76
|
+
runner.use(
|
|
77
|
+
pipes.VerifyDelegation({
|
|
78
|
+
type: 'signature',
|
|
79
|
+
signerKey: 'senderState',
|
|
80
|
+
delegatorKey: 'delegatorState',
|
|
81
|
+
getRequirements: getDelegationRequirements,
|
|
82
|
+
})
|
|
83
|
+
);
|
|
77
84
|
|
|
78
85
|
// 2. ensure token exist and match
|
|
79
86
|
runner.use(pipes.ExtractState({ from: 'itx.tokenAddress', to: 'tokenState', status: 'INVALID_TOKEN', table: 'token' }));
|
|
@@ -111,16 +118,26 @@ runner.use(
|
|
|
111
118
|
);
|
|
112
119
|
|
|
113
120
|
// Ensure tx fee and gas
|
|
114
|
-
runner.use(EnsureTxGas(() => ({ create: 1, update:
|
|
121
|
+
runner.use(EnsureTxGas(() => ({ create: 1, update: 2, payment: 0 })));
|
|
115
122
|
runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
116
123
|
|
|
117
124
|
// 5. create rollup state
|
|
118
125
|
runner.use(
|
|
119
126
|
async (context, next) => {
|
|
120
|
-
const {
|
|
127
|
+
const {
|
|
128
|
+
tx,
|
|
129
|
+
formattedItx,
|
|
130
|
+
rollupData,
|
|
131
|
+
statedb,
|
|
132
|
+
senderState,
|
|
133
|
+
delegatorState,
|
|
134
|
+
delegationState,
|
|
135
|
+
senderUpdates,
|
|
136
|
+
updateVaults,
|
|
137
|
+
} = context;
|
|
121
138
|
|
|
122
139
|
const issuer = delegatorState ? delegatorState.address : senderState.address;
|
|
123
|
-
const [newSenderState, rollupState] = await Promise.all([
|
|
140
|
+
const [newSenderState, rollupState, newDelegationState] = await Promise.all([
|
|
124
141
|
statedb.account.update(
|
|
125
142
|
senderState.address,
|
|
126
143
|
account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
|
|
@@ -141,6 +158,11 @@ runner.use(
|
|
|
141
158
|
context
|
|
142
159
|
),
|
|
143
160
|
|
|
161
|
+
// Update delegation state
|
|
162
|
+
context.isDelegationChanged
|
|
163
|
+
? statedb.delegation.update(delegationState.address, delegation.update(delegationState, {}, context), context)
|
|
164
|
+
: delegationState,
|
|
165
|
+
|
|
144
166
|
updateVaults(),
|
|
145
167
|
]);
|
|
146
168
|
|
|
@@ -149,6 +171,7 @@ runner.use(
|
|
|
149
171
|
|
|
150
172
|
context.senderState = newSenderState;
|
|
151
173
|
context.rollupState = rollupState;
|
|
174
|
+
context.delegationState = newDelegationState;
|
|
152
175
|
|
|
153
176
|
debug('create-rollup', rollupState);
|
|
154
177
|
|
|
@@ -3,13 +3,13 @@ const cloneDeep = require('lodash/cloneDeep');
|
|
|
3
3
|
const { Joi, schemas } = require('@arcblock/validator');
|
|
4
4
|
const { CustomError: Error } = require('@ocap/util/lib/error');
|
|
5
5
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
6
|
-
const { account, token } = require('@ocap/state');
|
|
6
|
+
const { account, token, delegation } = require('@ocap/state');
|
|
7
7
|
const { toTokenAddress } = require('@arcblock/did-util');
|
|
8
8
|
const { fromTokenToUnit } = require('@ocap/util');
|
|
9
9
|
|
|
10
10
|
// eslint-disable-next-line global-require
|
|
11
11
|
const debug = require('debug')(`${require('../../../package.json').name}:create-token`);
|
|
12
|
-
const { decodeAnySafe } = require('../../util');
|
|
12
|
+
const { decodeAnySafe, getDelegationRequirements } = require('../../util');
|
|
13
13
|
|
|
14
14
|
const EnsureTxGas = require('../../pipes/ensure-gas');
|
|
15
15
|
const EnsureTxCost = require('../../pipes/ensure-cost');
|
|
@@ -66,7 +66,14 @@ runner.use(pipes.VerifyAccountMigration({ stateKey: 'senderState', addressKey: '
|
|
|
66
66
|
// Ensure delegation
|
|
67
67
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
68
68
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'delegatorState', addressKey: 'tx.delegator' }));
|
|
69
|
-
runner.use(
|
|
69
|
+
runner.use(
|
|
70
|
+
pipes.VerifyDelegation({
|
|
71
|
+
type: 'signature',
|
|
72
|
+
signerKey: 'senderState',
|
|
73
|
+
delegatorKey: 'delegatorState',
|
|
74
|
+
getRequirements: getDelegationRequirements,
|
|
75
|
+
})
|
|
76
|
+
);
|
|
70
77
|
|
|
71
78
|
// Ensure token not exist
|
|
72
79
|
runner.use(pipes.ExtractState({ from: 'itx.address', to: 'tokenState', table: 'token', status: 'OK' }));
|
|
@@ -101,7 +108,7 @@ runner.use(
|
|
|
101
108
|
// Ensure tx fee and gas
|
|
102
109
|
runner.use(
|
|
103
110
|
EnsureTxGas((context) => {
|
|
104
|
-
const result = { create: 1, update:
|
|
111
|
+
const result = { create: 1, update: 2, payment: 0 };
|
|
105
112
|
if (context.delegatorState) {
|
|
106
113
|
result.update += 1;
|
|
107
114
|
}
|
|
@@ -114,7 +121,7 @@ runner.use(EnsureTxCost({ attachSenderChanges: true }));
|
|
|
114
121
|
// Update sender state, token state
|
|
115
122
|
runner.use(
|
|
116
123
|
async (context, next) => {
|
|
117
|
-
const { tx, itx, statedb, senderState, delegatorState, senderUpdates, updateVaults } = context;
|
|
124
|
+
const { tx, itx, statedb, senderState, delegatorState, delegationState, senderUpdates, updateVaults } = context;
|
|
118
125
|
const data = decodeAnySafe(itx.data);
|
|
119
126
|
const owner = delegatorState ? delegatorState.address : senderState.address;
|
|
120
127
|
|
|
@@ -130,7 +137,7 @@ runner.use(
|
|
|
130
137
|
senderUpdates.tokens[itx.address] = itx.initialSupply;
|
|
131
138
|
}
|
|
132
139
|
|
|
133
|
-
const [newSenderState, tokenState, newDelegatorState] = await Promise.all([
|
|
140
|
+
const [newSenderState, tokenState, newDelegatorState, newDelegationState] = await Promise.all([
|
|
134
141
|
statedb.account.update(
|
|
135
142
|
senderState.address,
|
|
136
143
|
account.update(senderState, { nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
|
|
@@ -147,12 +154,18 @@ runner.use(
|
|
|
147
154
|
)
|
|
148
155
|
: null,
|
|
149
156
|
|
|
157
|
+
// Update delegation state
|
|
158
|
+
context.isDelegationChanged
|
|
159
|
+
? statedb.delegation.update(delegationState.address, delegation.update(delegationState, {}, context), context)
|
|
160
|
+
: delegationState,
|
|
161
|
+
|
|
150
162
|
updateVaults(),
|
|
151
163
|
]);
|
|
152
164
|
|
|
153
165
|
context.senderState = newSenderState;
|
|
154
166
|
context.tokenState = tokenState;
|
|
155
167
|
context.delegatorState = newDelegatorState;
|
|
168
|
+
context.delegationState = newDelegationState;
|
|
156
169
|
|
|
157
170
|
debug('create token v2', tokenState);
|
|
158
171
|
|
|
@@ -99,6 +99,8 @@ runner.use(
|
|
|
99
99
|
signerKey: 'signerStates',
|
|
100
100
|
delegatorKey: 'delegatorStates',
|
|
101
101
|
delegationKey: 'delegationStates',
|
|
102
|
+
// FIXME: this is not working
|
|
103
|
+
getRequirements: () => [],
|
|
102
104
|
})
|
|
103
105
|
);
|
|
104
106
|
|
|
@@ -134,7 +136,7 @@ runner.use(pipes.VerifyUpdater({ assetKey: 'priv.receiverAssets', ownerKey: 'rec
|
|
|
134
136
|
runner.use(
|
|
135
137
|
EnsureTxGas((context) => {
|
|
136
138
|
// FIXME: payment check
|
|
137
|
-
const ops = { create: 0, update:
|
|
139
|
+
const ops = { create: 0, update: 3, payment: 0 };
|
|
138
140
|
ops.update += context.senderAssets.length;
|
|
139
141
|
ops.update += context.receiverAssets.length;
|
|
140
142
|
|
|
@@ -5,7 +5,7 @@ const { decodeBigInt } = require('@ocap/message');
|
|
|
5
5
|
const { Joi, schemas } = require('@arcblock/validator');
|
|
6
6
|
const { BN } = require('@ocap/util');
|
|
7
7
|
const { Runner, pipes } = require('@ocap/tx-pipeline');
|
|
8
|
-
const { account } = require('@ocap/state');
|
|
8
|
+
const { account, delegation } = require('@ocap/state');
|
|
9
9
|
|
|
10
10
|
// eslint-disable-next-line global-require
|
|
11
11
|
const debug = require('debug')(`${require('../../../package.json').name}:transfer-v2`);
|
|
@@ -97,7 +97,17 @@ runner.use(pipes.VerifyTokenBalance({ ownerKey: 'senderState', conditionKey: 'to
|
|
|
97
97
|
|
|
98
98
|
runner.use(pipes.ExtractState({ from: 'tx.delegator', to: 'delegatorState', status: 'OK', table: 'account' }));
|
|
99
99
|
runner.use(pipes.VerifyAccountMigration({ stateKey: 'delegatorState', addressKey: 'tx.delegator' }));
|
|
100
|
-
runner.use(
|
|
100
|
+
runner.use(
|
|
101
|
+
pipes.VerifyDelegation({
|
|
102
|
+
type: 'signature',
|
|
103
|
+
signerKey: 'senderState',
|
|
104
|
+
delegatorKey: 'delegatorState',
|
|
105
|
+
getRequirements: (ctx) => [
|
|
106
|
+
...ctx.tokens.map((x) => ({ type: 'token', ...x, to: ctx.itx.to })),
|
|
107
|
+
...ctx.assets.map((x) => ({ type: 'asset', address: x, to: ctx.itx.to })),
|
|
108
|
+
],
|
|
109
|
+
})
|
|
110
|
+
);
|
|
101
111
|
|
|
102
112
|
runner.use(pipes.ExtractReceiver({ from: 'itx.to', to: 'receiver' }));
|
|
103
113
|
runner.use(pipes.ExtractState({ from: 'receiver', to: 'receiverState', status: 'OK', table: 'account' }));
|
|
@@ -111,7 +121,7 @@ runner.use(pipes.VerifyUpdater({ assetKey: 'assetStates', ownerKey: 'senderState
|
|
|
111
121
|
runner.use(
|
|
112
122
|
EnsureTxGas((context) => {
|
|
113
123
|
// FIXME: payment check
|
|
114
|
-
const result = { create: 0, update:
|
|
124
|
+
const result = { create: 0, update: 2, payment: 0 };
|
|
115
125
|
result.update += context.assetStates?.length || 0;
|
|
116
126
|
|
|
117
127
|
if (context.receiverState) {
|
|
@@ -136,7 +146,18 @@ runner.use(pipes.UpdateOwner({ assets: 'assetStates', owner: 'receiverAddr' }));
|
|
|
136
146
|
// update statedb: transfer tokens to new owner
|
|
137
147
|
runner.use(
|
|
138
148
|
async (context, next) => {
|
|
139
|
-
const {
|
|
149
|
+
const {
|
|
150
|
+
tx,
|
|
151
|
+
itx,
|
|
152
|
+
tokens,
|
|
153
|
+
senderState,
|
|
154
|
+
receiverAddr,
|
|
155
|
+
receiverState,
|
|
156
|
+
statedb,
|
|
157
|
+
senderChange,
|
|
158
|
+
delegationState,
|
|
159
|
+
updateVaults,
|
|
160
|
+
} = context;
|
|
140
161
|
|
|
141
162
|
const { tokens: senderTokens = {} } = senderState;
|
|
142
163
|
const { tokens: receiverTokens = {} } = receiverState || {};
|
|
@@ -150,7 +171,7 @@ runner.use(
|
|
|
150
171
|
? applyTokenChange({ tokens: senderTokens }, senderChange)
|
|
151
172
|
: { tokens: senderTokens };
|
|
152
173
|
|
|
153
|
-
const [newSenderState, newReceiverState] = await Promise.all([
|
|
174
|
+
const [newSenderState, newReceiverState, newDelegationState] = await Promise.all([
|
|
154
175
|
// Update sender state
|
|
155
176
|
statedb.account.update(
|
|
156
177
|
senderState.address,
|
|
@@ -165,11 +186,17 @@ runner.use(
|
|
|
165
186
|
context
|
|
166
187
|
),
|
|
167
188
|
|
|
189
|
+
// Update delegation state
|
|
190
|
+
context.isDelegationChanged
|
|
191
|
+
? statedb.delegation.update(delegationState.address, delegation.update(delegationState, {}, context), context)
|
|
192
|
+
: delegationState,
|
|
193
|
+
|
|
168
194
|
updateVaults(),
|
|
169
195
|
]);
|
|
170
196
|
|
|
171
197
|
context.senderState = newSenderState;
|
|
172
198
|
context.receiverState = newReceiverState;
|
|
199
|
+
context.delegationState = newDelegationState;
|
|
173
200
|
|
|
174
201
|
debug('transfer-v2', { from: tx.from, to: itx.to, tokens });
|
|
175
202
|
|
package/lib/util.js
CHANGED
|
@@ -160,6 +160,22 @@ const getTxFee = ({ amount, feeRate, maxFee, minFee, stringify = true }) => {
|
|
|
160
160
|
};
|
|
161
161
|
};
|
|
162
162
|
|
|
163
|
+
const getDelegationRequirements = (context) => {
|
|
164
|
+
const { txType, config } = context;
|
|
165
|
+
const txFee = config.transaction.txFee[txType];
|
|
166
|
+
if (!txFee) {
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return [
|
|
171
|
+
{
|
|
172
|
+
type: 'token',
|
|
173
|
+
address: config.token.address,
|
|
174
|
+
value: fromTokenToUnit(txFee, config.token.decimal).toString(),
|
|
175
|
+
},
|
|
176
|
+
];
|
|
177
|
+
};
|
|
178
|
+
|
|
163
179
|
const splitTxFee = ({ total, shares = {}, stringify = true }) => {
|
|
164
180
|
const totalAmount = new BN(total);
|
|
165
181
|
if (totalAmount.isNeg()) {
|
|
@@ -397,4 +413,5 @@ module.exports = {
|
|
|
397
413
|
isGasStakeInput,
|
|
398
414
|
isGasStakeValid,
|
|
399
415
|
RATE_BASE,
|
|
416
|
+
getDelegationRequirements,
|
|
400
417
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.18.
|
|
6
|
+
"version": "1.18.97",
|
|
7
7
|
"description": "Predefined tx pipeline sets to execute certain type of transactions",
|
|
8
8
|
"main": "lib/index.js",
|
|
9
9
|
"files": [
|
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
"author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@arcblock/did": "1.18.
|
|
25
|
-
"@arcblock/did-util": "1.18.
|
|
26
|
-
"@arcblock/jwt": "1.18.
|
|
27
|
-
"@arcblock/validator": "1.18.
|
|
28
|
-
"@ocap/asset": "1.18.
|
|
29
|
-
"@ocap/mcrypto": "1.18.
|
|
30
|
-
"@ocap/merkle-tree": "1.18.
|
|
31
|
-
"@ocap/message": "1.18.
|
|
32
|
-
"@ocap/state": "1.18.
|
|
33
|
-
"@ocap/tx-pipeline": "1.18.
|
|
34
|
-
"@ocap/util": "1.18.
|
|
35
|
-
"@ocap/wallet": "1.18.
|
|
24
|
+
"@arcblock/did": "1.18.97",
|
|
25
|
+
"@arcblock/did-util": "1.18.97",
|
|
26
|
+
"@arcblock/jwt": "1.18.97",
|
|
27
|
+
"@arcblock/validator": "1.18.97",
|
|
28
|
+
"@ocap/asset": "1.18.97",
|
|
29
|
+
"@ocap/mcrypto": "1.18.97",
|
|
30
|
+
"@ocap/merkle-tree": "1.18.97",
|
|
31
|
+
"@ocap/message": "1.18.97",
|
|
32
|
+
"@ocap/state": "1.18.97",
|
|
33
|
+
"@ocap/tx-pipeline": "1.18.97",
|
|
34
|
+
"@ocap/util": "1.18.97",
|
|
35
|
+
"@ocap/wallet": "1.18.97",
|
|
36
36
|
"debug": "^4.3.4",
|
|
37
37
|
"deep-diff": "^1.0.2",
|
|
38
38
|
"empty-value": "^1.0.1",
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"jest": "^27.5.1",
|
|
48
48
|
"start-server-and-test": "^1.14.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "691aabefd37f53b6fbcf771ce130f09197f0b268"
|
|
51
51
|
}
|