@sentio/sdk 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/lib/base-processor-template.d.ts +6 -0
  2. package/lib/base-processor-template.js +5 -0
  3. package/lib/base-processor-template.js.map +1 -1
  4. package/lib/base-processor.d.ts +1 -1
  5. package/lib/base-processor.js +9 -2
  6. package/lib/base-processor.js.map +1 -1
  7. package/lib/builtin/internal/erc20_processor.d.ts +148 -99
  8. package/lib/builtin/internal/erc20_processor.js +96 -42
  9. package/lib/builtin/internal/erc20_processor.js.map +1 -1
  10. package/lib/builtin/internal/erc20bytes_processor.d.ts +80 -52
  11. package/lib/builtin/internal/erc20bytes_processor.js +49 -22
  12. package/lib/builtin/internal/erc20bytes_processor.js.map +1 -1
  13. package/lib/builtin/internal/weth9_processor.d.ts +92 -64
  14. package/lib/builtin/internal/weth9_processor.js +63 -30
  15. package/lib/builtin/internal/weth9_processor.js.map +1 -1
  16. package/lib/context.js +1 -0
  17. package/lib/context.js.map +1 -1
  18. package/lib/index.d.ts +1 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/target-ethers-sentio/codegen.js +8 -4
  21. package/lib/target-ethers-sentio/codegen.js.map +1 -1
  22. package/lib/target-ethers-sentio/functions.js +13 -6
  23. package/lib/target-ethers-sentio/functions.js.map +1 -1
  24. package/lib/test/erc20-template.js +2 -2
  25. package/lib/test/erc20-template.js.map +1 -1
  26. package/lib/test/erc20.js +6 -4
  27. package/lib/test/erc20.js.map +1 -1
  28. package/lib/test/erc20.test.js +25 -0
  29. package/lib/test/erc20.test.js.map +1 -1
  30. package/lib/test/test-processor-server.d.ts +5 -1
  31. package/lib/test/test-processor-server.js +41 -0
  32. package/lib/test/test-processor-server.js.map +1 -1
  33. package/lib/trace.d.ts +5 -5
  34. package/lib/trace.js +21 -0
  35. package/lib/trace.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/base-processor-template.ts +13 -0
  38. package/src/base-processor.ts +10 -3
  39. package/src/builtin/internal/erc20_processor.ts +264 -123
  40. package/src/builtin/internal/erc20bytes_processor.ts +139 -63
  41. package/src/builtin/internal/weth9_processor.ts +155 -76
  42. package/src/context.ts +1 -0
  43. package/src/index.ts +1 -1
  44. package/src/target-ethers-sentio/codegen.ts +8 -4
  45. package/src/target-ethers-sentio/functions.ts +20 -7
  46. package/src/test/erc20-template.ts +2 -2
  47. package/src/test/erc20.test.ts +29 -0
  48. package/src/test/erc20.ts +6 -4
  49. package/src/test/test-processor-server.ts +47 -0
  50. package/src/trace.ts +27 -5
@@ -20,6 +20,8 @@ export function codeGenIndex(contract: Contract): string {
20
20
 
21
21
  export function codeGenSentioFile(contract: Contract): string {
22
22
  const source = `
23
+ ${Object.values(contract.functions).map(codegenCallTraceTypes).join('\n')}
24
+
23
25
  const templateContract = ${contract.name}__factory.connect("", DummyProvider)
24
26
 
25
27
  export class ${contract.name}ContractView extends ContractView<${contract.name}> {
@@ -71,10 +73,12 @@ export function codeGenSentioFile(contract: Contract): string {
71
73
  }
72
74
  })
73
75
  .join('\n')}
76
+
77
+ ${Object.values(contract.functions)
78
+ .map((f) => codegenFunctions(f, contract.name))
79
+ .join('\n')}
74
80
  }
75
81
 
76
- ${Object.values(contract.functions).map(codegenCallTraceTypes).join('\n')}
77
-
78
82
  export class ${contract.name}Processor extends BaseProcessor<${contract.name}, ${contract.name}BoundContractView> {
79
83
  ${Object.values(contract.events)
80
84
  .map((events) => {
@@ -141,7 +145,7 @@ export function codeGenSentioFile(contract: Contract): string {
141
145
  'ContractView',
142
146
  'DummyProvider',
143
147
  'getContractName',
144
- 'TypedTrace',
148
+ 'TypedCallTrace',
145
149
  ],
146
150
  './common': ['PromiseOrValue'],
147
151
  './index': [`${contract.name}`, `${contract.name}__factory`],
@@ -216,7 +220,7 @@ function generateOnEventFunction(event: EventDeclaration, contractName: string,
216
220
  const filterName = getFullSignatureForEvent(event)
217
221
 
218
222
  return `
219
- on${eventName}(
223
+ onEvent${eventName}(
220
224
  handler: (event: ${eventName}Event, ctx: ${contractName}Context) => void,
221
225
  filter?: ${eventName}EventFilter | ${eventName}EventFilter[]
222
226
  ) {
@@ -1,5 +1,9 @@
1
- import { generateInputTypes } from '@typechain/ethers-v5/dist/codegen/types'
1
+ import {
2
+ generateOutputComplexTypeAsArray,
3
+ generateOutputComplexTypesAsObject,
4
+ } from '@typechain/ethers-v5/dist/codegen/types'
2
5
  import { FunctionDeclaration, getSignatureForFn } from 'typechain'
6
+ import { utils } from 'ethers'
3
7
 
4
8
  export function codegenFunctions(fns: FunctionDeclaration[], contractName: string): string {
5
9
  if (fns.length === 1) {
@@ -18,19 +22,28 @@ export function codegenCallTraceTypes(fns: FunctionDeclaration[]): string {
18
22
  }
19
23
 
20
24
  function codegenCallTraceType(fn: FunctionDeclaration, overloadedName?: string): string {
25
+ const identifier = capitalizeFirstChar(overloadedName ?? fn.name)
26
+
27
+ const components = fn.inputs.map((input, i) => ({ name: input.name ?? `arg${i.toString()}`, type: input.type }))
28
+ const arrayOutput = generateOutputComplexTypeAsArray(components, { useStructs: true })
29
+ const objectOutput = generateOutputComplexTypesAsObject(components, { useStructs: true }) || '{}'
30
+
21
31
  return `
22
- export interface ${capitalizeFirstChar(overloadedName ?? fn.name)}CallTrace extends TypedTrace {
23
- args: [${generateInputTypes(fn.inputs, { useStructs: true })}]
24
- }
32
+ export interface ${identifier}CallObject ${objectOutput}
33
+
34
+ export type ${identifier}CallTrace = TypedCallTrace<${arrayOutput}, ${identifier}CallObject>
25
35
  `
26
36
  }
27
37
 
28
38
  function generateFunction(fn: FunctionDeclaration, contractName: string, overloadedName?: string): string {
39
+ const signature = getSignatureForFn(fn)
40
+ const sighash = utils.keccak256(utils.toUtf8Bytes(signature)).substring(0, 10)
41
+
29
42
  return `
30
- on${capitalizeFirstChar(overloadedName ?? fn.name)}Call(
31
- handler: (trace: ${capitalizeFirstChar(overloadedName ?? fn.name)}CallTrace, ctx: ${contractName}Context) => void
43
+ onCall${capitalizeFirstChar(overloadedName ?? fn.name)}(
44
+ handler: (call: ${capitalizeFirstChar(overloadedName ?? fn.name)}CallTrace, ctx: ${contractName}Context) => void
32
45
  ) {
33
- return super.onTrace("${getSignatureForFn(fn)}", handler);
46
+ return super.onTrace("${sighash}", handler);
34
47
  }
35
48
  `
36
49
  }
@@ -5,7 +5,7 @@ export const filter = ERC20Processor.filters.Transfer(
5
5
  '0xb329e39ebefd16f40d38f07643652ce17ca5bac1'
6
6
  )
7
7
 
8
- const processorTemplate = new ERC20ProcessorTemplate().onTransfer(async function (event, ctx) {
8
+ const processorTemplate = new ERC20ProcessorTemplate().onEventTransfer(async function (event, ctx) {
9
9
  console.log('')
10
10
  })
11
11
 
@@ -14,7 +14,7 @@ ERC20Processor.bind({
14
14
  network: 1,
15
15
  name: 'x2y2',
16
16
  startBlock: 14201940,
17
- }).onTransfer(async function (event, ctx) {
17
+ }).onEventTransfer(async function (event, ctx) {
18
18
  processorTemplate.bind({
19
19
  address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
20
20
  network: 3,
@@ -8,6 +8,7 @@ import { TestProcessorServer } from './test-processor-server'
8
8
  import { firstCounterValue, firstGaugeValue } from './metric-utils'
9
9
  import { BigNumber } from 'ethers'
10
10
  import { mockTransferLog } from '../builtin/erc20/test-utils'
11
+ import { Trace } from '../trace'
11
12
 
12
13
  describe('Test Basic Examples', () => {
13
14
  const service = new TestProcessorServer(() => require('./erc20'))
@@ -85,4 +86,32 @@ describe('Test Basic Examples', () => {
85
86
  timestamp: 1647106437,
86
87
  extraData: '0xe4b883e5bda9e7a59ee4bb99e9b1bc493421',
87
88
  }
89
+
90
+ test('Check trace dispatch', async () => {
91
+ const res = (await service.testTrace(traceData)).result
92
+ expect(res?.counters).length(1)
93
+ })
94
+
95
+ const traceData: Trace = {
96
+ action: {
97
+ from: '0x80009ff8154bd5653c6dda2fa5f5053e5a5c1a91',
98
+ callType: 'call',
99
+ gas: 0xbb0a,
100
+ input:
101
+ '0x095ea7b30000000000000000000000003eabf546fff0a41edaaf5b667333a846285713180000000000000000000000000000000000000000000000000000002a03956d85',
102
+ to: '0x1E4EDE388cbc9F4b5c79681B7f94d36a11ABEBC9',
103
+ value: 0x0,
104
+ },
105
+ blockHash: '0xb1fe1fefca4063ab9cc06a10356a6dd397b8c3dd38e21470e107a711ad559c13',
106
+ blockNumber: 15548801,
107
+ result: {
108
+ gasUsed: 0x95df,
109
+ output: '0x0000000000000000000000000000000000000000000000000000000000000001',
110
+ },
111
+ subtraces: 1,
112
+ traceAddress: [],
113
+ transactionHash: '0xc05c37b34e13380d0b7e0475b27a0c77fda826f82c603f9c45922e952d63b7a5',
114
+ transactionPosition: 69,
115
+ type: 'call',
116
+ }
88
117
  })
package/src/test/erc20.ts CHANGED
@@ -5,7 +5,7 @@ export const filter = ERC20Processor.filters.Transfer(
5
5
  '0xb329e39ebefd16f40d38f07643652ce17ca5bac1'
6
6
  )
7
7
 
8
- const processorTemplate = new ERC20ProcessorTemplate().onTransfer(async function (event, ctx) {
8
+ const processorTemplate = new ERC20ProcessorTemplate().onEventTransfer(async function (event, ctx) {
9
9
  console.log('')
10
10
  })
11
11
 
@@ -15,7 +15,7 @@ ERC20Processor.bind({
15
15
  name: 'x2y2',
16
16
  startBlock: 14201940,
17
17
  })
18
- .onTransfer(async function (event, ctx) {
18
+ .onEventTransfer(async function (event, ctx) {
19
19
  processorTemplate.bind({ address: '0x1E4EDE388cbc9F4b5c79681B7f94d36a11ABEBC9', network: 3, name: 'dynamic' })
20
20
  // template.bind('0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', 3, 'dynamic')
21
21
  ctx.meter.Counter('c1').add(1)
@@ -23,15 +23,17 @@ ERC20Processor.bind({
23
23
  .onBlock(async function (block, ctx) {
24
24
  ctx.meter.Gauge('g1').record(10, { k: 'v' })
25
25
  })
26
+ .onCallApprove(function (call, ctx) {
27
+ ctx.meter.Counter('added').add(call.args.amount, { spender: call.args.spender })
28
+ })
26
29
 
27
30
  ERC20Processor.bind({ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', network: 56, name: 'usdc' })
28
- .onTransfer(async function (event, ctx) {
31
+ .onEventTransfer(async function (event, ctx) {
29
32
  ctx.meter.Counter('c2').add(2)
30
33
  }, filter)
31
34
  .onBlock(async function (block, ctx) {
32
35
  ctx.meter.Gauge('g2').record(20, { k: 'v' })
33
36
  })
34
- // .startBlock(14201940)
35
37
 
36
38
  ERC20Processor.bind({ address: 'xxxx', network: 56 })
37
39
 
@@ -19,6 +19,7 @@ import {
19
19
  ProcessTransactionsResponse,
20
20
  setProvider,
21
21
  StartRequest,
22
+ TraceBinding,
22
23
  } from '@sentio/sdk'
23
24
  import { CallContext } from 'nice-grpc-common'
24
25
  import { Empty } from '../gen/google/protobuf/empty'
@@ -27,6 +28,7 @@ import { CHAIN_MAP } from '../utils/chainmap'
27
28
  import { Block, Log } from '@ethersproject/abstract-provider'
28
29
  import Long from 'long'
29
30
  import { getNetwork, Networkish } from '@ethersproject/providers'
31
+ import { Trace } from '../trace'
30
32
 
31
33
  const TEST_CONTEXT: CallContext = <CallContext>{}
32
34
 
@@ -95,6 +97,51 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
95
97
  return this.service.processTransactions(request, context)
96
98
  }
97
99
 
100
+ testTrace(trace: Trace, network: Networkish = 1): Promise<ProcessTracesResponse> {
101
+ return this.testTraces([trace], network)
102
+ }
103
+
104
+ testTraces(traces: Trace[], network: Networkish = 1): Promise<ProcessTracesResponse> {
105
+ const bindings = []
106
+ for (const trace of traces) {
107
+ const binding = this.buildTraceBinding(trace, network)
108
+ if (!binding) {
109
+ throw Error('Invalid test trace: ' + JSON.stringify(trace))
110
+ }
111
+ bindings.push(binding)
112
+ }
113
+ return this.processTraces({
114
+ traceBindings: bindings,
115
+ })
116
+ }
117
+
118
+ buildTraceBinding(trace: Trace, network: Networkish = 1): TraceBinding | undefined {
119
+ if (trace.type !== 'call' || !trace.action.input) {
120
+ throw Error('Invalid test trace: ' + JSON.stringify(trace))
121
+ }
122
+ const signature = trace.action.input.slice(0, 10)
123
+
124
+ for (const contract of this.contractConfig) {
125
+ if (contract.contract?.chainId !== getNetwork(network).chainId.toString()) {
126
+ continue
127
+ }
128
+ if (trace.action.to?.toLowerCase() !== contract.contract?.address.toLowerCase()) {
129
+ continue
130
+ }
131
+ for (const config of contract.traceConfigs) {
132
+ if (config.signature == signature) {
133
+ return {
134
+ trace: {
135
+ raw: toBytes(trace),
136
+ },
137
+ handlerId: config.handlerId,
138
+ }
139
+ }
140
+ }
141
+ }
142
+ return undefined
143
+ }
144
+
98
145
  testLog(log: Log, network: Networkish = 1): Promise<ProcessLogsResponse> {
99
146
  return this.testLogs([log], network)
100
147
  }
package/src/trace.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  // https://github.com/openethereum/parity-ethereum/blob/55c90d4016505317034e3e98f699af07f5404b63/rpc/src/v1/types/trace.rs#L482
2
2
  import { Result } from '@ethersproject/abi'
3
3
 
4
- export interface TypedTrace<TArgsArray extends Array<any> = any, TArgsObject = any> extends Trace {
4
+ export interface TypedCallTrace<TArgsArray extends Array<any> = any, TArgsObject = any> extends Trace {
5
5
  args: TArgsArray & TArgsObject
6
6
  }
7
7
 
@@ -23,11 +23,11 @@ export interface Trace {
23
23
 
24
24
  export interface TraceAction {
25
25
  from: string
26
- to: string
26
+ to?: string
27
27
  value: number
28
28
  gas: number
29
- input: string
30
- callType: string
29
+ input?: string
30
+ callType?: string
31
31
 
32
32
  init?: string
33
33
  address?: string
@@ -38,7 +38,7 @@ export interface TraceAction {
38
38
  // TODO are more field missing for FailedCall, FailedCreate
39
39
  export interface TraceResult {
40
40
  gasUsed: number
41
- output: string
41
+ output?: string
42
42
  address?: string
43
43
  code?: string
44
44
  }
@@ -62,3 +62,25 @@ export interface TraceResult {
62
62
  // transactionPosition: 73,
63
63
  // type: 'call',
64
64
  // }
65
+
66
+ // const trac2: Trace =
67
+ // {
68
+ // "action": {
69
+ // "from": "0x95ba4cf87d6723ad9c0db21737d862be80e93911",
70
+ // "gas": 0x630d0b,
71
+ // "init": "0x608060405234801561001057600080fd5b50604051602080610b2983398101806040528101908080519060200190929190505050808060405180807f6f72672e7a657070656c696e6f732e70726f78792e696d706c656d656e74617481526020017f696f6e000000000000000000000000000000000000000000000000000000000081525060230190506040518091039020600019167f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3600102600019161415156100c657fe5b6100de81610169640100000000026401000000009004565b5060405180807f6f72672e7a657070656c696e6f732e70726f78792e61646d696e000000000000815250601a0190506040518091039020600019167f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b6001026000191614151561014a57fe5b6101623361024e640100000000026401000000009004565b5050610290565b60006101878261027d6401000000000261084b176401000000009004565b1515610221576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001807f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f81526020017f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000081525060400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c360010290508181555050565b60007f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b60010290508181555050565b600080823b905060008111915050919050565b61088a8061029f6000396000f30060806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633659cfe6146100775780634f1ef286146100ba5780635c60da1b146101085780638f2839701461015f578063f851a440146101a2575b6100756101f9565b005b34801561008357600080fd5b506100b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610213565b005b610106600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001919091929391929390505050610268565b005b34801561011457600080fd5b5061011d610308565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561016b57600080fd5b506101a0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610360565b005b3480156101ae57600080fd5b506101b761051e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610201610576565b61021161020c610651565b610682565b565b61021b6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025c57610257816106d9565b610265565b6102646101f9565b5b50565b6102706106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fa576102ac836106d9565b3073ffffffffffffffffffffffffffffffffffffffff163483836040518083838082843782019150509250505060006040518083038185875af19250505015156102f557600080fd5b610303565b6103026101f9565b5b505050565b60006103126106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156103545761034d610651565b905061035d565b61035c6101f9565b5b90565b6103686106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561051257600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001807f43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f81526020017f787920746f20746865207a65726f20616464726573730000000000000000000081525060400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61048f6106a8565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161050d81610748565b61051b565b61051a6101f9565b5b50565b60006105286106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561056a576105636106a8565b9050610573565b6105726101f9565b5b90565b61057e6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515610647576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e20667281526020017f6f6d207468652070726f78792061646d696e000000000000000000000000000081525060400191505060405180910390fd5b61064f610777565b565b6000807f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c36001029050805491505090565b3660008037600080366000845af43d6000803e80600081146106a3573d6000f35b3d6000fd5b6000807f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b6001029050805491505090565b6106e281610779565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b60010290508181555050565b565b60006107848261084b565b151561081e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001807f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f81526020017f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000081525060400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c360010290508181555050565b600080823b9050600081119150509190505600a165627a7a72305820a4a547cfc7202c5acaaae74d428e988bc62ad5024eb0165532d3a8f91db4ed2400290000000000000000000000000882477e7895bdc5cea7cb1552ed914ab157fe56",
72
+ // "value": 0x0
73
+ // },
74
+ // "blockHash": "0xb2f6986457f5a24ff088a0beb5567c8c1fe2da02687c78e743507ee7c982b977",
75
+ // "blockNumber": 6082465,
76
+ // "result": {
77
+ // "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
78
+ // "code": "0x60806040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633659cfe6146100775780634f1ef286146100ba5780635c60da1b146101085780638f2839701461015f578063f851a440146101a2575b6100756101f9565b005b34801561008357600080fd5b506100b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610213565b005b610106600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001919091929391929390505050610268565b005b34801561011457600080fd5b5061011d610308565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561016b57600080fd5b506101a0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610360565b005b3480156101ae57600080fd5b506101b761051e565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610201610576565b61021161020c610651565b610682565b565b61021b6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561025c57610257816106d9565b610265565b6102646101f9565b5b50565b6102706106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102fa576102ac836106d9565b3073ffffffffffffffffffffffffffffffffffffffff163483836040518083838082843782019150509250505060006040518083038185875af19250505015156102f557600080fd5b610303565b6103026101f9565b5b505050565b60006103126106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156103545761034d610651565b905061035d565b61035c6101f9565b5b90565b6103686106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561051257600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610466576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260368152602001807f43616e6e6f74206368616e6765207468652061646d696e206f6620612070726f81526020017f787920746f20746865207a65726f20616464726573730000000000000000000081525060400191505060405180910390fd5b7f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f61048f6106a8565b82604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390a161050d81610748565b61051b565b61051a6101f9565b5b50565b60006105286106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561056a576105636106a8565b9050610573565b6105726101f9565b5b90565b61057e6106a8565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151515610647576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260328152602001807f43616e6e6f742063616c6c2066616c6c6261636b2066756e6374696f6e20667281526020017f6f6d207468652070726f78792061646d696e000000000000000000000000000081525060400191505060405180910390fd5b61064f610777565b565b6000807f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c36001029050805491505090565b3660008037600080366000845af43d6000803e80600081146106a3573d6000f35b3d6000fd5b6000807f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b6001029050805491505090565b6106e281610779565b7fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b81604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a150565b60007f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b60010290508181555050565b565b60006107848261084b565b151561081e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603b8152602001807f43616e6e6f742073657420612070726f787920696d706c656d656e746174696f81526020017f6e20746f2061206e6f6e2d636f6e74726163742061646472657373000000000081525060400191505060405180910390fd5b7f7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c360010290508181555050565b600080823b9050600081119150509190505600a165627a7a72305820a4a547cfc7202c5acaaae74d428e988bc62ad5024eb0165532d3a8f91db4ed240029",
79
+ // "gasUsed": 0x74f42
80
+ // },
81
+ // "subtraces": 0,
82
+ // "traceAddress": [],
83
+ // "transactionHash": "0xe7e0fe390354509cd08c9a0168536938600ddc552b3f7cb96030ebef62e75895",
84
+ // "transactionPosition": 22,
85
+ // "type": "create"
86
+ // }