1 | const lodash = require('lodash');
|
2 | const ContractABICoder = require('./ContractABICoder');
|
3 | const ContractConstructor = require('./ContractConstructor');
|
4 | const ContractMethod = require('./ContractMethod');
|
5 | const ContractEvent = require('./ContractEvent');
|
6 | const ContractMethodOverride = require('./ContractMethodOverride');
|
7 | const ContractEventOverride = require('./ContractEventOverride');
|
8 |
|
9 | /**
|
10 | * Contract with all its methods and events defined in its abi.
|
11 | */
|
12 | class Contract {
|
13 | /**
|
14 | * @param options {object}
|
15 | * @param options.abi {array} - The json interface for the contract to instantiate
|
16 | * @param [options.address] {string} - The address of the smart contract to call, can be added later using `contract.address = '0x1234...'`
|
17 | * @param [options.bytecode] {string} - The byte code of the contract, can be added later using `contract.constructor.code = '0x1234...'`
|
18 | * @param conflux {Conflux} - Conflux instance.
|
19 | * @return {object}
|
20 | *
|
21 | * @example
|
22 | * > const contract = conflux.Contract({ abi, bytecode });
|
23 | {
|
24 | constructor: [Function: bound call],
|
25 | abi: ContractABICoder { * },
|
26 | address: undefined,
|
27 | count: [Function: bound call],
|
28 | inc: [Function: bound call],
|
29 | 'count()': [Function: bound call],
|
30 | '0x06661abd': [Function: bound call],
|
31 | 'inc(uint256)': [Function: bound call],
|
32 | '0x812600df': [Function: bound call],
|
33 | }
|
34 |
|
35 | * > contract.constructor.bytecode; // input code
|
36 | "0x6080604052600080..."
|
37 |
|
38 | * @example
|
39 | * > const contract = conflux.Contract({ abi, address });
|
40 | * > contract.address
|
41 | "0xc3ed1a06471be1d3bcd014051fbe078387ec0ad8"
|
42 |
|
43 | * > await contract.count(); // call a method without parameter, get decoded return value.
|
44 | "100"
|
45 | * > await contract.inc(1); // call a method with parameters, get decoded return value.
|
46 | "101"
|
47 | * > await contract.count().options({ from: account }); // call a method from a account.
|
48 | "100"
|
49 |
|
50 | * > transaction = await conflux.getTransactionByHash('0x8a5f48c2de0f1bdacfe90443810ad650e4b327a0d19ce49a53faffb224883e42');
|
51 | * > await contract.abi.decodeData(transaction.data)
|
52 | {
|
53 | name: 'inc',
|
54 | fullName: 'inc(uint256 num)',
|
55 | type: 'inc(uint256)',
|
56 | signature: '0x7f98a45e',
|
57 | array: [ JSBI.BigInt(101) ],
|
58 | object: { num: JSBI.BigInt(101) }
|
59 | }
|
60 |
|
61 | * > await contract.count(); // data in block chain changed by transaction.
|
62 | JSBI.BigInt(101)
|
63 |
|
64 | * > receipt = await conflux.getTransactionReceipt('0x8a5f48c2de0f1bdacfe90443810ad650e4b327a0d19ce49a53faffb224883e42');
|
65 | * > contract.abi.decodeLog(receipt.logs[0]);
|
66 | {
|
67 | name: 'SelfEvent',
|
68 | fullName: 'SelfEvent(address indexed sender, uint256 current)',
|
69 | type: 'SelfEvent(address,uint256))',
|
70 | signature: '0xc4c01f6de493c58245fb681341f3a76bba9551ce81b11cbbb5d6d297844594df',
|
71 | array: [ '0xbbd9e9be525ab967e633bcdaeac8bd5723ed4d6b', JSBI.BigInt(100) ],
|
72 | object: {
|
73 | sender: '0xbbd9e9be525ab967e633bcdaeac8bd5723ed4d6b',
|
74 | current: JSBI.BigInt(100),
|
75 | },
|
76 | }
|
77 | */
|
78 | constructor({ abi, address, bytecode }, conflux) {
|
79 | const abiTable = lodash.groupBy(abi, 'type');
|
80 |
|
81 | this.constructor = new ContractConstructor(lodash.first(abiTable.constructor), bytecode, this, conflux);
|
82 | this.abi = new ContractABICoder(this); // XXX: Create a method named `abi` in solidity is a `Warning`.
|
83 | this.address = address; // XXX: Create a method named `address` in solidity is a `ParserError`
|
84 |
|
85 | const methodArray = lodash.map(abiTable.function, fragment => new ContractMethod(fragment, this, conflux));
|
86 | const eventArray = lodash.map(abiTable.event, fragment => new ContractEvent(fragment, this, conflux));
|
87 |
|
88 | // name to instance
|
89 | lodash.forEach(lodash.groupBy(methodArray, 'name'), (array, name) => {
|
90 | this[name] = array.length === 1 ? lodash.first(array) : new ContractMethodOverride(array, this, conflux);
|
91 | });
|
92 | lodash.forEach(lodash.groupBy(eventArray, 'name'), (array, name) => {
|
93 | this[name] = array.length === 1 ? lodash.first(array) : new ContractEventOverride(array, this, conflux);
|
94 | });
|
95 |
|
96 | // type to instance
|
97 | // signature for contract abi decoder to decode
|
98 | methodArray.forEach(method => {
|
99 | this[method.type] = method;
|
100 | this[method.signature] = method; // signature for contract abi decoder to decode
|
101 | });
|
102 | eventArray.forEach(event => {
|
103 | this[event.type] = event;
|
104 | this[event.signature] = event; // signature for contract abi decoder to decode
|
105 | });
|
106 | }
|
107 | }
|
108 |
|
109 | module.exports = Contract;
|