@ocap/tx-protocols 1.13.64 → 1.13.65

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.
@@ -61,9 +61,9 @@ runner.use(
61
61
  );
62
62
 
63
63
  // Ensure sender/receiver exist
64
- runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
64
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK', table: 'account' }));
65
65
  runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
66
- runner.use(pipes.ExtractState({ from: 'itx.to', to: 'receiverState', status: 'INVALID_RECEIVER_STATE' }));
66
+ runner.use(pipes.ExtractState({ from: 'itx.to', to: 'receiverState', status: 'OK', table: 'account' }));
67
67
 
68
68
  // Extract delegation
69
69
  runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', table: 'delegation', status: 'OK' }));
@@ -71,7 +71,7 @@ runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', tabl
71
71
  // Create delegation state
72
72
  runner.use(
73
73
  async (context, next) => {
74
- const { tx, itx, ops, statedb, senderState, delegationState } = context;
74
+ const { tx, itx, ops, statedb, senderState, receiverState, delegationState } = context;
75
75
 
76
76
  const opsObj = ops.reduce(
77
77
  (acc, x) => {
@@ -86,8 +86,23 @@ runner.use(
86
86
  delegationState ? delegationState.ops : {}
87
87
  );
88
88
 
89
- const [newSenderState, newDelegationState] = await Promise.all([
90
- statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
89
+ const sender = senderState ? senderState.address : tx.from;
90
+ const receiver = receiverState ? receiverState.address : itx.to;
91
+
92
+ const [newSenderState, newReceiverState, newDelegationState] = await Promise.all([
93
+ // update sender
94
+ statedb.account.updateOrCreate(
95
+ senderState,
96
+ account.updateOrCreate(senderState, { address: sender, nonce: tx.nonce, pk: tx.pk }, context),
97
+ context
98
+ ),
99
+
100
+ // update receiver
101
+ receiverState
102
+ ? Promise.resolve(receiverState)
103
+ : statedb.account.create(receiver, account.create({ address: receiver }, context), context),
104
+
105
+ // update delegation
91
106
  delegationState
92
107
  ? statedb.delegation.update(itx.address, delegation.update(delegationState, { ...itx, ops: opsObj }, context), context) // prettier-ignore
93
108
  : statedb.delegation.create(itx.address, delegation.create({ ...itx, ops: opsObj }, context), context),
@@ -97,6 +112,7 @@ runner.use(
97
112
 
98
113
  // Update context
99
114
  context.senderState = newSenderState;
115
+ context.receiverState = newReceiverState;
100
116
  context.delegationState = newDelegationState;
101
117
 
102
118
  return next();
@@ -35,7 +35,7 @@ runner.use(
35
35
  );
36
36
 
37
37
  // Ensure sender exist
38
- runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
38
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
39
39
  runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
40
40
 
41
41
  // Create account state, and update old accounts
@@ -48,7 +48,7 @@ runner.use(
48
48
 
49
49
  // Ensure receiver does not exist
50
50
  if (receiver) {
51
- return next(new Error('INVALID_SENDER_STATE', 'Can not migrate to an existing account'));
51
+ return next(new Error('INVALID_RECEIVER_STATE', 'Can not migrate to an existing account'));
52
52
  }
53
53
 
54
54
  // Create new account
@@ -53,10 +53,9 @@ runner.use(
53
53
  );
54
54
 
55
55
  // Ensure sender/receiver/delegation exist
56
- runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
56
+ runner.use(pipes.ExtractState({ from: 'itx.address', to: 'delegationState', status: 'INVALID_DELEGATION', table: 'delegation' })); // prettier-ignore
57
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
57
58
  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
59
 
61
60
  // Update delegation state
62
61
  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: 'INVALID_RECEIVER_STATE' }));
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] = await Promise.all([
167
- // Update sender state
168
- statedb.account.update(
169
- senderState.address,
170
- account.update(
171
- senderState,
172
- Object.assign({ nonce: tx.nonce }, signerUpdates[senderState.address] || {}),
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
- context
176
- ),
177
-
178
- // Create asset
179
- statedb.asset.create(
180
- itx.address,
181
- asset.create({ ...mintedAsset, owner: ownerState.address, address: mintedAddress }, context),
182
- context
183
- ),
184
-
185
- // Update signer state
186
- Promise.all(
187
- signerStates
188
- .filter((x) => x.address !== senderState.address)
189
- .map((x) => statedb.account.update(x.address, account.update(x, signerUpdates[x.address], context), context))
190
- ),
191
-
192
- // Update factory state
193
- statedb.factory.update(factoryState.address, factory.update(factoryState, factoryUpdates, context), context),
194
-
195
- // Mark asset as consumed
196
- Promise.all(
197
- assetStates.map((x) =>
198
- statedb.asset.update(x.address, asset.update(x, { consumedTime: txTime }, context), context)
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;
@@ -64,7 +64,7 @@ runner.use(
64
64
  );
65
65
 
66
66
  // Ensure sender exist
67
- runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
67
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
68
68
  runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
69
69
 
70
70
  // Check if parent is a factory
@@ -83,7 +83,7 @@ runner.use(
83
83
  );
84
84
 
85
85
  // Ensure parent exist
86
- runner.use(pipes.ExtractState({ from: 'itx.parent', to: 'parentAsset', status: 'INVALID_ASSET' }));
86
+ runner.use(pipes.ExtractState({ from: 'itx.parent', to: 'parentAsset', status: 'INVALID_ASSET', table: 'asset' }));
87
87
 
88
88
  // Update asset state
89
89
  runner.use(
@@ -92,7 +92,11 @@ runner.use(
92
92
 
93
93
  const [newSenderState, assetState] = await Promise.all([
94
94
  // Update owner state
95
- statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
95
+ statedb.account.update(
96
+ senderState.address,
97
+ account.update(senderState, { nonce: tx.nonce, pk: tx.pk }, context),
98
+ context
99
+ ),
96
100
  // Create asset state
97
101
  statedb.asset.create(
98
102
  itx.address,
@@ -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: 'INVALID_OWNER' }));
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
- // account updates
76
- const senderUpdates = { nonce: tx.nonce };
75
+ const owner = ownerState ? ownerState.address : itx.owner;
77
76
 
78
- // Factory updates
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: ownerState.address, address: mintedAddress }, context),
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
 
@@ -52,7 +52,11 @@ runner.use(
52
52
 
53
53
  const [newSenderState, newAssetState] = await Promise.all([
54
54
  // update owner state
55
- statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
55
+ statedb.account.update(
56
+ senderState.address,
57
+ account.update(senderState, { nonce: tx.nonce, pk: tx.pk }, context),
58
+ context
59
+ ),
56
60
 
57
61
  // update asset state
58
62
  statedb.asset.update(
@@ -79,23 +79,15 @@ runner.use(
79
79
  );
80
80
 
81
81
  // Ensure sender exist
82
- runner.use(
83
- pipes.ExtractState({ from: 'tx.from', to: 'senderState', table: 'account', status: 'INVALID_SENDER_STATE' })
84
- );
82
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', table: 'account', status: 'INVALID_SENDER_STATE' })); // prettier-ignore
85
83
  runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
86
84
 
87
85
  // 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
- );
86
+ runner.use(pipes.ExtractState({ from: 'factoryTokens', to: 'tokenStates', table: 'token', status: 'INVALID_FACTORY_INPUT' })); // prettier-ignore
91
87
 
92
88
  // ensure input.assets all exist on chain
93
- runner.use(
94
- pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputAssetStates', table: 'asset', status: 'OK' })
95
- );
96
- runner.use(
97
- pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputFactoryStates', table: 'factory', status: 'OK' })
98
- );
89
+ runner.use(pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputAssetStates', table: 'asset', status: 'OK' })); // prettier-ignore
90
+ runner.use(pipes.ExtractState({ from: 'factoryProps.input.assets', to: 'inputFactoryStates', table: 'factory', status: 'OK' })); // prettier-ignore
99
91
  runner.use((context, next) => {
100
92
  const { inputAssetStates = [], inputFactoryStates = [], factoryProps } = context;
101
93
  if (inputAssetStates.some((x) => !!x.consumedTime)) {
@@ -118,7 +110,12 @@ runner.use(
118
110
 
119
111
  const [newSenderState, factoryState] = await Promise.all([
120
112
  // Update owner state
121
- statedb.account.update(senderState.address, account.update(senderState, { nonce: tx.nonce }, context), context),
113
+ statedb.account.update(
114
+ senderState.address,
115
+ account.update(senderState, { nonce: tx.nonce, pk: tx.pk }, context),
116
+ context
117
+ ),
118
+
122
119
  // Create factory state
123
120
  statedb.factory.create(
124
121
  itx.address,
@@ -122,7 +122,7 @@ runner.use(
122
122
  senderState.address,
123
123
  account.update(
124
124
  senderState,
125
- Object.assign({ nonce: tx.nonce }, signerUpdates[senderState.address] || {}),
125
+ Object.assign({ nonce: tx.nonce, pk: tx.pk }, signerUpdates[senderState.address] || {}),
126
126
  context
127
127
  ),
128
128
  context
@@ -56,7 +56,7 @@ runner.use(
56
56
  );
57
57
 
58
58
  // Ensure sender exist
59
- runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE' }));
59
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
60
60
  runner.use(pipes.VerifyAccountMigration({ senderKey: 'senderState' }));
61
61
 
62
62
  // Ensure token not exist
@@ -98,7 +98,7 @@ runner.use(
98
98
  const [newSenderState, tokenState] = await Promise.all([
99
99
  statedb.account.update(
100
100
  senderState.address,
101
- account.update(senderState, { tokens: senderTokens, nonce: tx.nonce }, context),
101
+ account.update(senderState, { tokens: senderTokens, nonce: tx.nonce, pk: tx.pk }, context),
102
102
  context
103
103
  ),
104
104
  statedb.token.create(itx.address, token.create({ ...itx, data, issuer: senderState.address }, context), context),
@@ -155,7 +155,7 @@ runner.use((context, next) => {
155
155
  });
156
156
 
157
157
  // 7. verify sender and signer states
158
- runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'INVALID_SENDER_STATE', table: 'account' })); // prettier-ignore
158
+ runner.use(pipes.ExtractState({ from: 'tx.from', to: 'senderState', status: 'OK', table: 'account' }));
159
159
  runner.use(pipes.ExtractState({ from: 'signers', to: 'signerStates', status: 'INVALID_SIGNER_STATE', table: 'account' })); // prettier-ignore
160
160
  runner.use(pipes.VerifyAccountMigration({ signerKey: 'signerStates', senderKey: 'senderState' }));
161
161
 
@@ -169,18 +169,19 @@ runner.use(
169
169
  const total = getBNSum(user, fee);
170
170
 
171
171
  const stakeUpdates = applyTokenUpdates([{ address: itx.token.address, value: total }], stakeState, 'sub');
172
- const senderUpdates = applyTokenUpdates([{ address: itx.token.address, value: user }], senderState, 'add');
172
+ const senderUpdates = applyTokenUpdates([{ address: itx.token.address, value: user }], senderState || {}, 'add');
173
173
  const lockerUpdates = applyTokenUpdates(
174
174
  [{ address: itx.token.address, value: fee }],
175
175
  lockerState || { tokens: {} },
176
176
  'add'
177
177
  );
178
178
 
179
+ const sender = senderState ? senderState.address : tx.from;
179
180
  const [newSenderState, newStakeState, newLockerState, evidenceState] = await Promise.all([
180
- // update user account
181
- statedb.account.update(
182
- senderState.address,
183
- account.update(senderState, { nonce: tx.nonce, ...senderUpdates }, context),
181
+ // updateOrCreate user account
182
+ statedb.account.updateOrCreate(
183
+ senderState,
184
+ account.updateOrCreate(senderState, { address: sender, nonce: tx.nonce, pk: tx.pk, ...senderUpdates }, context),
184
185
  context
185
186
  ),
186
187
 
@@ -224,7 +225,7 @@ runner.use(
224
225
  // stake for tx proposer is decreased
225
226
  { address: stakeAddress, token: itx.token.address, delta: `-${total}`, action: 'unlock' },
226
227
  // mint to depositor from stake
227
- { address: senderState.address, token: itx.token.address, delta: user, action: 'unlock' },
228
+ { address: sender, token: itx.token.address, delta: user, action: 'unlock' },
228
229
  // tx fee is locked for later claiming
229
230
  { address: lockerAddress, token: itx.token.address, delta: fee, action: 'pending' },
230
231
  ];
@@ -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: 'INVALID_RECEIVER_STATE' }));
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
- runner.use(pipes.UpdateOwner({ assets: 'assetStates', owner: 'receiverState' }));
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.update(
112
- receiverState.address,
113
- account.update(receiverState, { tokens: receiverTokens }, context),
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: 'INVALID_RECEIVER_STATE' }));
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 { tx, inputs, outputs, senderState, signerStates, receiverStates, assetStates = [], statedb } = context;
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
- // Update receiver state
211
+ // UpdateOrCreate receiver state
203
212
  Promise.all(
204
- receiverStates
205
- .filter((x) => x.address !== senderState.address)
206
- .map((x) =>
207
- statedb.account.update(x.address, account.update(x, receiverUpdates[x.address], context), context)
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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.13.64",
6
+ "version": "1.13.65",
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,16 @@
19
19
  "author": "wangshijun <wangshijun2010@gmail.com> (http://github.com/wangshijun)",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@arcblock/did": "1.13.64",
23
- "@arcblock/did-util": "1.13.64",
24
- "@ocap/asset": "1.13.64",
25
- "@ocap/mcrypto": "1.13.64",
26
- "@ocap/merkle-tree": "1.13.64",
27
- "@ocap/message": "1.13.64",
28
- "@ocap/state": "1.13.64",
29
- "@ocap/tx-pipeline": "1.13.64",
30
- "@ocap/util": "1.13.64",
31
- "@ocap/wallet": "1.13.64",
22
+ "@arcblock/did": "1.13.65",
23
+ "@arcblock/did-util": "1.13.65",
24
+ "@ocap/asset": "1.13.65",
25
+ "@ocap/mcrypto": "1.13.65",
26
+ "@ocap/merkle-tree": "1.13.65",
27
+ "@ocap/message": "1.13.65",
28
+ "@ocap/state": "1.13.65",
29
+ "@ocap/tx-pipeline": "1.13.65",
30
+ "@ocap/util": "1.13.65",
31
+ "@ocap/wallet": "1.13.65",
32
32
  "debug": "^4.3.2",
33
33
  "empty-value": "^1.0.1",
34
34
  "lodash": "^4.17.21",
@@ -41,5 +41,5 @@
41
41
  "devDependencies": {
42
42
  "jest": "^27.3.1"
43
43
  },
44
- "gitHead": "49c94d9fd5f12ec63c34ad609d041a92f68322a8"
44
+ "gitHead": "4011996e1800845142aa5c889b58726129a99ec3"
45
45
  }