@stellar-expert/tx-meta-effects-parser 5.0.0-beta10
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/.eslintrc.js +8 -0
- package/.npmignore +6 -0
- package/LICENSE +21 -0
- package/README.MD +1145 -0
- package/babel.config.js +3 -0
- package/jest.config.js +6 -0
- package/package.json +21 -0
- package/src/analyzer-primitives.js +150 -0
- package/src/asset-supply-processor.js +130 -0
- package/src/contract-preimage-encoder.js +43 -0
- package/src/effect-types.js +97 -0
- package/src/effect.js +24 -0
- package/src/errors.js +13 -0
- package/src/events-analyzer.js +308 -0
- package/src/index.js +161 -0
- package/src/ledger-entry-changes-parser.js +333 -0
- package/src/signer-changes-analyzer.js +147 -0
- package/src/tx-effects-analyzer.js +826 -0
- package/src/tx-meta-changes-parser.js +35 -0
- package/src/tx-result-parser.js +127 -0
- package/src/tx-xdr-parser-utils.js +276 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
const {StrKey} = require('@stellar/stellar-base')
|
|
2
|
+
const {
|
|
3
|
+
xdrParseAsset,
|
|
4
|
+
xdrParseAccountAddress,
|
|
5
|
+
xdrParseClaimant,
|
|
6
|
+
xdrParsePrice,
|
|
7
|
+
xdrParseSignerKey,
|
|
8
|
+
xdrParseScVal
|
|
9
|
+
} = require('./tx-xdr-parser-utils')
|
|
10
|
+
const {TxMetaEffectParserError} = require('./errors')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {{}} ParsedLedgerEntryMeta
|
|
14
|
+
* @property {'account'|'trustline'|'offer'|'data'|'liquidityPool'|'claimableBalance'|'contractData'|'contractCode'} type - Ledger entry type
|
|
15
|
+
* @property {'created'|'updated'|'removed'} action - Ledger modification action
|
|
16
|
+
* @property {{}} before - Ledger entry state before changes applied
|
|
17
|
+
* @property {{}} after - Ledger entry state after changes application
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {LedgerEntryChange[]} ledgerEntryChanges
|
|
22
|
+
* @return {ParsedLedgerEntryMeta[]}
|
|
23
|
+
*/
|
|
24
|
+
function parseLedgerEntryChanges(ledgerEntryChanges) {
|
|
25
|
+
const changes = []
|
|
26
|
+
let state
|
|
27
|
+
for (let i = 0; i < ledgerEntryChanges.length; i++) {
|
|
28
|
+
const entry = ledgerEntryChanges[i]
|
|
29
|
+
const actionType = entry.arm()
|
|
30
|
+
|
|
31
|
+
const stateData = parseEntry(entry.value(), actionType)
|
|
32
|
+
if (stateData === undefined)
|
|
33
|
+
continue
|
|
34
|
+
const change = {action: actionType}
|
|
35
|
+
switch (actionType) {
|
|
36
|
+
case 'state':
|
|
37
|
+
state = stateData
|
|
38
|
+
continue
|
|
39
|
+
case 'created':
|
|
40
|
+
change.before = null
|
|
41
|
+
change.after = stateData
|
|
42
|
+
change.type = stateData.entry
|
|
43
|
+
break
|
|
44
|
+
case 'updated':
|
|
45
|
+
change.before = state
|
|
46
|
+
change.after = stateData
|
|
47
|
+
change.type = stateData.entry
|
|
48
|
+
break
|
|
49
|
+
case 'removed':
|
|
50
|
+
if (!state && entry._value._arm === 'ttl')
|
|
51
|
+
continue //skip expiration processing for now
|
|
52
|
+
change.before = state
|
|
53
|
+
change.after = null
|
|
54
|
+
change.type = state.entry
|
|
55
|
+
break
|
|
56
|
+
default:
|
|
57
|
+
throw new TxMetaEffectParserError(`Unknown change entry type: ${actionType}`)
|
|
58
|
+
}
|
|
59
|
+
changes.push(change)
|
|
60
|
+
state = null
|
|
61
|
+
}
|
|
62
|
+
return changes
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function parseEntry(entry, actionType) {
|
|
66
|
+
if (actionType === 'removed')
|
|
67
|
+
return null //parseEntryData(entry)
|
|
68
|
+
const parsed = parseEntryData(entry.data())
|
|
69
|
+
if (parsed === null)
|
|
70
|
+
return null
|
|
71
|
+
//parsed.modified = entry.lastModifiedLedgerSeq()
|
|
72
|
+
return parseLedgerEntryExt(parsed, entry)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function parseEntryData(data) {
|
|
76
|
+
const updatedEntryType = data.arm()
|
|
77
|
+
switch (updatedEntryType) {
|
|
78
|
+
case 'account':
|
|
79
|
+
return parseAccountEntry(data)
|
|
80
|
+
case 'trustline':
|
|
81
|
+
case 'trustLine':
|
|
82
|
+
return parseTrustlineEntry(data)
|
|
83
|
+
case 'offer':
|
|
84
|
+
return parseOfferEntry(data)
|
|
85
|
+
case 'data':
|
|
86
|
+
case 'datum':
|
|
87
|
+
return parseDataEntry(data)
|
|
88
|
+
case 'claimableBalance':
|
|
89
|
+
return parseClaimableBalanceEntry(data)
|
|
90
|
+
case 'liquidityPool':
|
|
91
|
+
return parseLiquidityPoolEntry(data)
|
|
92
|
+
case 'contractData':
|
|
93
|
+
return parseContractData(data)
|
|
94
|
+
case 'contractCode':
|
|
95
|
+
return undefined
|
|
96
|
+
case 'ttl':
|
|
97
|
+
return undefined
|
|
98
|
+
default:
|
|
99
|
+
throw new TxMetaEffectParserError(`Unknown meta entry type: ${updatedEntryType}`)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function parseLedgerEntryExt(data, entry) {
|
|
104
|
+
const v1 = entry.ext()?.v1()
|
|
105
|
+
if (v1) {
|
|
106
|
+
const sponsor = v1.sponsoringId()
|
|
107
|
+
if (sponsor) {
|
|
108
|
+
data.sponsor = xdrParseAccountAddress(sponsor)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return data
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function parseAccountEntry(value) {
|
|
115
|
+
const accountEntryXdr = value.value()
|
|
116
|
+
const data = {
|
|
117
|
+
entry: 'account',
|
|
118
|
+
address: xdrParseAccountAddress(accountEntryXdr.accountId()),
|
|
119
|
+
sequence: accountEntryXdr.seqNum().toString(),
|
|
120
|
+
balance: accountEntryXdr.balance().toString(),
|
|
121
|
+
homeDomain: accountEntryXdr.homeDomain().toString('UTF8'),
|
|
122
|
+
inflationDest: xdrParseAccountAddress(accountEntryXdr.inflationDest()),
|
|
123
|
+
flags: accountEntryXdr.flags(),
|
|
124
|
+
signers: accountEntryXdr.signers().map(signer => ({
|
|
125
|
+
key: xdrParseSignerKey(signer.key()),
|
|
126
|
+
weight: signer.weight()
|
|
127
|
+
}))
|
|
128
|
+
}
|
|
129
|
+
const thresholds = accountEntryXdr.thresholds()
|
|
130
|
+
data.thresholds = thresholds.slice(1).join()
|
|
131
|
+
data.masterWeight = thresholds[0]
|
|
132
|
+
const extV1 = accountEntryXdr.ext()?.v1()
|
|
133
|
+
if (extV1) {
|
|
134
|
+
const extV2 = extV1.ext()?.v2()
|
|
135
|
+
if (extV2) {
|
|
136
|
+
const sponsoringIDs = extV2.signerSponsoringIDs()
|
|
137
|
+
if (sponsoringIDs.length > 0) {
|
|
138
|
+
for (let i = 0; i < data.signers.length; i++) {
|
|
139
|
+
const sponsor = sponsoringIDs[i]
|
|
140
|
+
if (sponsor) { //attach sponsors directly to the signers
|
|
141
|
+
data.signers[i].sponsor = xdrParseAccountAddress(sponsor)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//ignored fields: numSubEntries, extV1.liabilities, extV2.numSponsored, extV2.numSponsoring, extV3.seqLedger, extv3.seqTime
|
|
148
|
+
return data
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function parseTrustlineEntry(value) {
|
|
152
|
+
const trustlineEntryXdr = value.value()
|
|
153
|
+
const trustlineAsset = trustlineEntryXdr.asset()
|
|
154
|
+
const trustlineType = trustlineAsset.switch()
|
|
155
|
+
let asset
|
|
156
|
+
switch (trustlineType.value) {
|
|
157
|
+
case 0:
|
|
158
|
+
case 1:
|
|
159
|
+
case 2:
|
|
160
|
+
asset = xdrParseAsset(trustlineAsset)
|
|
161
|
+
break
|
|
162
|
+
case 3:
|
|
163
|
+
asset = trustlineEntryXdr.asset().liquidityPoolId().toString('hex')
|
|
164
|
+
//data.liquidityPoolUseCount = trustlineEntryXdr.liquidityPoolUseCount()
|
|
165
|
+
break
|
|
166
|
+
default:
|
|
167
|
+
throw new TxMetaEffectParserError(`Unsupported trustline type ` + trustlineType)
|
|
168
|
+
}
|
|
169
|
+
const data = {
|
|
170
|
+
entry: 'trustline',
|
|
171
|
+
account: xdrParseAccountAddress(trustlineEntryXdr.accountId()),
|
|
172
|
+
asset,
|
|
173
|
+
balance: trustlineEntryXdr.balance().toString(),
|
|
174
|
+
limit: trustlineEntryXdr.limit().toString(),
|
|
175
|
+
flags: trustlineEntryXdr.flags()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/*
|
|
179
|
+
//ignored
|
|
180
|
+
const extV1 = trustlineEntryXdr.ext()?.v1()
|
|
181
|
+
if (extV1) {
|
|
182
|
+
const liabilities = extV1.liabilities()
|
|
183
|
+
data.buying_liabilities = liabilities.buying().toString()
|
|
184
|
+
data.selling_liabilities = liabilities.selling().toString()
|
|
185
|
+
}*/
|
|
186
|
+
|
|
187
|
+
return data
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function parseDataEntry(value) {
|
|
191
|
+
const dataEntryXdr = value.value()
|
|
192
|
+
return {
|
|
193
|
+
entry: 'data',
|
|
194
|
+
account: xdrParseAccountAddress(dataEntryXdr.accountId()),
|
|
195
|
+
name: dataEntryXdr.dataName().toString(),
|
|
196
|
+
value: dataEntryXdr.dataValue().toString('base64')
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function parseLiquidityPoolEntry(value) {
|
|
201
|
+
const liquidityPoolEntryXdr = value.value()
|
|
202
|
+
const body = liquidityPoolEntryXdr.body().value()
|
|
203
|
+
const params = body.params()
|
|
204
|
+
return {
|
|
205
|
+
entry: 'liquidityPool',
|
|
206
|
+
pool: liquidityPoolEntryXdr.liquidityPoolId().toString('hex'),
|
|
207
|
+
asset: [xdrParseAsset(params.assetA()), xdrParseAsset(params.assetB())],
|
|
208
|
+
fee: params.fee(),
|
|
209
|
+
amount: [body.reserveA().toString(), body.reserveB().toString()],
|
|
210
|
+
shares: body.totalPoolShares().toString(),
|
|
211
|
+
accounts: body.poolSharesTrustLineCount().low
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function parseOfferEntry(value) {
|
|
216
|
+
const offerEntryXdr = value.value()
|
|
217
|
+
const data = {
|
|
218
|
+
entry: 'offer',
|
|
219
|
+
id: offerEntryXdr.offerId().toString(),
|
|
220
|
+
account: xdrParseAccountAddress(offerEntryXdr.sellerId()),
|
|
221
|
+
asset: [xdrParseAsset(offerEntryXdr.selling()), xdrParseAsset(offerEntryXdr.buying())],
|
|
222
|
+
amount: offerEntryXdr.amount().toString(),
|
|
223
|
+
price: xdrParsePrice(offerEntryXdr.price()),
|
|
224
|
+
flags: offerEntryXdr.flags()
|
|
225
|
+
}
|
|
226
|
+
return data
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function parseClaimableBalanceEntry(value) {
|
|
230
|
+
const claimableBalanceXdr = value.value()
|
|
231
|
+
const data = {
|
|
232
|
+
balanceId: Buffer.from(claimableBalanceXdr.balanceId().value()).toString('hex'),
|
|
233
|
+
entry: 'claimableBalance',
|
|
234
|
+
asset: xdrParseAsset(claimableBalanceXdr.asset()),
|
|
235
|
+
amount: claimableBalanceXdr.amount().toString(),
|
|
236
|
+
claimants: claimableBalanceXdr.claimants().map(claimant => xdrParseClaimant(claimant))
|
|
237
|
+
}
|
|
238
|
+
const extV1 = claimableBalanceXdr.ext()?.v1()
|
|
239
|
+
if (extV1) {
|
|
240
|
+
data.flags = extV1.flags()
|
|
241
|
+
}
|
|
242
|
+
return data
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function parseContractData(value) {
|
|
246
|
+
const data = value.value()
|
|
247
|
+
const owner = parseStateOwnerDataAddress(data.contract())
|
|
248
|
+
|
|
249
|
+
const valueAttr = data.val()
|
|
250
|
+
switch (data.key().switch()?.name) {
|
|
251
|
+
case 'scvLedgerKeyContractInstance':
|
|
252
|
+
const entry = {
|
|
253
|
+
entry: 'contract',
|
|
254
|
+
contract: owner
|
|
255
|
+
}
|
|
256
|
+
const type = valueAttr.instance().executable().switch().name
|
|
257
|
+
switch (type) {
|
|
258
|
+
case 'contractExecutableStellarAsset':
|
|
259
|
+
entry.type = 'token'
|
|
260
|
+
/**
|
|
261
|
+
* data._attributes.val._value._attributes.storage
|
|
262
|
+
*
|
|
263
|
+
* ScVal: [scvContractInstance]
|
|
264
|
+
* instance
|
|
265
|
+
* executable: [contractExecutableStellarAsset]
|
|
266
|
+
* storage: Array[3]
|
|
267
|
+
* [0]
|
|
268
|
+
* key: [scvSymbol]
|
|
269
|
+
* sym: METADATA
|
|
270
|
+
* val: [scvMap]
|
|
271
|
+
* map: Array[3]
|
|
272
|
+
* [0]
|
|
273
|
+
* key: [scvSymbol]
|
|
274
|
+
* sym: decimal
|
|
275
|
+
* val: [scvU32]
|
|
276
|
+
* u32: 7
|
|
277
|
+
* [1]
|
|
278
|
+
* key: [scvSymbol]
|
|
279
|
+
* sym: name
|
|
280
|
+
* val: [scvString]
|
|
281
|
+
* str: ICGVCWUQXIHO:GBD2ALDOSNTEW2QWQA6RGQXTZVWGFZYTT5DYZDCPPGNOYTXOAQ6RFUAC
|
|
282
|
+
* [2]
|
|
283
|
+
* key: [scvSymbol]
|
|
284
|
+
* sym: symbol
|
|
285
|
+
* val: [scvString]
|
|
286
|
+
* str: ICGVCWUQXIHO
|
|
287
|
+
* [1]
|
|
288
|
+
* key: [scvVec]
|
|
289
|
+
* vec: Array[1]
|
|
290
|
+
* [0]: [scvSymbol]
|
|
291
|
+
* sym: Admin
|
|
292
|
+
* val: [scvAddress]
|
|
293
|
+
* address: [scAddressTypeAccount]
|
|
294
|
+
* accountId: [publicKeyTypeEd25519]
|
|
295
|
+
* ed25519: GBD2ALDOSNTEW2QWQA6RGQXTZVWGFZYTT5DYZDCPPGNOYTXOAQ6RFUAC
|
|
296
|
+
*/
|
|
297
|
+
return undefined
|
|
298
|
+
break
|
|
299
|
+
case 'contractExecutableWasm':
|
|
300
|
+
entry.kind = 'wasm'
|
|
301
|
+
entry.hash = valueAttr.instance().executable().wasmHash().toString('hex')
|
|
302
|
+
break
|
|
303
|
+
default:
|
|
304
|
+
throw new TxMetaEffectParserError('Unsupported executable type: ' + type)
|
|
305
|
+
}
|
|
306
|
+
return entry
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
entry: 'contractData',
|
|
311
|
+
owner,
|
|
312
|
+
key: data.key().toXDR('base64'),
|
|
313
|
+
value: valueAttr.toXDR('base64'),
|
|
314
|
+
durability: data.durability().name
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function parseStateOwnerDataAddress(contract) {
|
|
319
|
+
if (contract.switch().name === 'scAddressTypeContract')
|
|
320
|
+
return StrKey.encodeContract(contract.contractId())
|
|
321
|
+
return xdrParseAccountAddress(contract.accountId())
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/*function parseContractCode(value) {
|
|
325
|
+
const contract = value.value()
|
|
326
|
+
return {
|
|
327
|
+
entry: 'contractCode',
|
|
328
|
+
hash: contract.hash().toString('hex'),
|
|
329
|
+
code: contract.body().code().toString('base64')
|
|
330
|
+
}
|
|
331
|
+
}*/
|
|
332
|
+
|
|
333
|
+
module.exports = {parseLedgerEntryChanges}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const effectTypes = require('./effect-types')
|
|
2
|
+
|
|
3
|
+
class SignerChangesAnalyzer {
|
|
4
|
+
constructor(before, after) {
|
|
5
|
+
this.before = before
|
|
6
|
+
this.after = after
|
|
7
|
+
this.signers = after ? [...after.signers] : []
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
after
|
|
11
|
+
|
|
12
|
+
before
|
|
13
|
+
|
|
14
|
+
signers
|
|
15
|
+
|
|
16
|
+
effects
|
|
17
|
+
|
|
18
|
+
analyze() {
|
|
19
|
+
//search for changes
|
|
20
|
+
this.effects = []
|
|
21
|
+
this.analyzeMasterWeight()
|
|
22
|
+
|
|
23
|
+
const beforeSigners = this.before ? this.before.signers : []
|
|
24
|
+
const afterSigners = this.after ? this.after.signers : []
|
|
25
|
+
//skip if there is nothing to analyze
|
|
26
|
+
if (!beforeSigners.length && !afterSigners.length)
|
|
27
|
+
return this.effects
|
|
28
|
+
|
|
29
|
+
const processed = new Set()
|
|
30
|
+
//compare existing signers
|
|
31
|
+
for (const bs of beforeSigners) {
|
|
32
|
+
//mark signer key as processed
|
|
33
|
+
processed.add(bs.key)
|
|
34
|
+
//locate corresponding post-change signer
|
|
35
|
+
const as = afterSigners.find(signer => signer.key === bs.key)
|
|
36
|
+
if (!as) { //not found -- singer has been removed
|
|
37
|
+
if (bs.sponsor) {
|
|
38
|
+
this.removeSignerSponsorship(bs)
|
|
39
|
+
}
|
|
40
|
+
this.removeAccountSigner(bs)
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
//check for weight changes
|
|
45
|
+
if (as.weight !== bs.weight) {
|
|
46
|
+
this.updateAccountSigner(as)
|
|
47
|
+
}
|
|
48
|
+
//signer sponsor changed
|
|
49
|
+
if (as.sponsor !== bs.sponsor) {
|
|
50
|
+
if (!bs.sponsor && as.sponsor) {
|
|
51
|
+
this.createSignerSponsorship(as)
|
|
52
|
+
} else if (bs.sponsor && !as.sponsor) {
|
|
53
|
+
this.removeSignerSponsorship(bs)
|
|
54
|
+
} else {
|
|
55
|
+
this.updateSignerSponsorship(as, bs.sponsor)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//check for new signers
|
|
60
|
+
for (const as of afterSigners) {
|
|
61
|
+
if (!processed.has(as.key)) {
|
|
62
|
+
this.createAccountSigner(as)
|
|
63
|
+
if (as.sponsor) {
|
|
64
|
+
this.createSignerSponsorship(as)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return this.effects
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
analyzeMasterWeight() {
|
|
72
|
+
const {before, after} = this
|
|
73
|
+
if (!before || !after || before.masterWeight === after.masterWeight)
|
|
74
|
+
return
|
|
75
|
+
const signer = {key: after.address, weight: after.masterWeight}
|
|
76
|
+
if (after.masterWeight > 0) {
|
|
77
|
+
this.updateAccountSigner(signer)
|
|
78
|
+
} else {
|
|
79
|
+
this.removeAccountSigner(signer)
|
|
80
|
+
}
|
|
81
|
+
if (after.masterWeight !== 1) {
|
|
82
|
+
this.signers.push(signer)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
createAccountSigner(signer) {
|
|
87
|
+
this.effects.push({
|
|
88
|
+
type: effectTypes.accountSignerCreated,
|
|
89
|
+
signer: signer.key,
|
|
90
|
+
weight: signer.weight,
|
|
91
|
+
signers: this.signers
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
removeAccountSigner(signer) {
|
|
96
|
+
this.effects.push({
|
|
97
|
+
type: effectTypes.accountSignerRemoved,
|
|
98
|
+
signer: signer.key,
|
|
99
|
+
weight: 0,
|
|
100
|
+
signers: this.signers
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
updateAccountSigner(signer) {
|
|
105
|
+
this.effects.push({
|
|
106
|
+
type: effectTypes.accountSignerUpdated,
|
|
107
|
+
signer: signer.key,
|
|
108
|
+
weight: signer.weight,
|
|
109
|
+
signers: this.signers
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
createSignerSponsorship(signer) {
|
|
114
|
+
this.effects.push({
|
|
115
|
+
type: effectTypes.signerSponsorshipCreated,
|
|
116
|
+
account: this.after.address,
|
|
117
|
+
signer: signer.key,
|
|
118
|
+
sponsor: signer.sponsor
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
removeSignerSponsorship(signer) {
|
|
123
|
+
this.effects.push({
|
|
124
|
+
type: effectTypes.signerSponsorshipRemoved,
|
|
125
|
+
account: this.before.address,
|
|
126
|
+
signer: signer.key,
|
|
127
|
+
prevSponsor: signer.sponsor
|
|
128
|
+
})
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
updateSignerSponsorship(signer, prevSponsor) {
|
|
132
|
+
this.effects.push({
|
|
133
|
+
type: effectTypes.signerSponsorshipUpdated,
|
|
134
|
+
account: this.after.address,
|
|
135
|
+
signer: signer.key,
|
|
136
|
+
sponsor: signer.sponsor,
|
|
137
|
+
prevSponsor: prevSponsor
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
function analyzeSignerChanges(before, after) {
|
|
144
|
+
return new SignerChangesAnalyzer(before, after).analyze()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {analyzeSignerChanges}
|