Fix wrong transaction input for contract deployments (#4052)
* Fix mutable options in Contract API * Add Swarm hash and meta data from Solidity * Updates tests for contract deployment * Add test for deploy without constructor Params
This commit is contained in:
parent
1b93d79a90
commit
9ab9ff2381
@ -218,14 +218,19 @@ export default class Contract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_encodeOptions (func, options, values) {
|
_encodeOptions (func, options, values) {
|
||||||
options.data = this.getCallData(func, options, values);
|
const data = this.getCallData(func, options, values);
|
||||||
return options;
|
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
data
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_addOptionsTo (options = {}) {
|
_addOptionsTo (options = {}) {
|
||||||
return Object.assign({
|
return {
|
||||||
to: this._address
|
to: this._address,
|
||||||
}, options);
|
...options
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_bindFunction = (func) => {
|
_bindFunction = (func) => {
|
||||||
|
@ -31,6 +31,7 @@ const eth = new Api(transport);
|
|||||||
|
|
||||||
describe('api/contract/Contract', () => {
|
describe('api/contract/Contract', () => {
|
||||||
const ADDR = '0x0123456789';
|
const ADDR = '0x0123456789';
|
||||||
|
|
||||||
const ABI = [
|
const ABI = [
|
||||||
{
|
{
|
||||||
type: 'function', name: 'test',
|
type: 'function', name: 'test',
|
||||||
@ -41,12 +42,42 @@ describe('api/contract/Contract', () => {
|
|||||||
type: 'function', name: 'test2',
|
type: 'function', name: 'test2',
|
||||||
outputs: [{ type: 'uint' }, { type: 'uint' }]
|
outputs: [{ type: 'uint' }, { type: 'uint' }]
|
||||||
},
|
},
|
||||||
{ type: 'constructor' },
|
{
|
||||||
|
type: 'constructor',
|
||||||
|
inputs: [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }]
|
||||||
|
},
|
||||||
{ type: 'event', name: 'baz' },
|
{ type: 'event', name: 'baz' },
|
||||||
{ type: 'event', name: 'foo' }
|
{ type: 'event', name: 'foo' }
|
||||||
];
|
];
|
||||||
const VALUES = [true, 'jacogr'];
|
|
||||||
const ENCODED = '0x023562050000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000066a61636f67720000000000000000000000000000000000000000000000000000';
|
const ABI_NO_PARAMS = [
|
||||||
|
{
|
||||||
|
type: 'function', name: 'test',
|
||||||
|
inputs: [{ name: 'boolin', type: 'bool' }, { name: 'stringin', type: 'string' }],
|
||||||
|
outputs: [{ type: 'uint' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'function', name: 'test2',
|
||||||
|
outputs: [{ type: 'uint' }, { type: 'uint' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'constructor'
|
||||||
|
},
|
||||||
|
{ type: 'event', name: 'baz' },
|
||||||
|
{ type: 'event', name: 'foo' }
|
||||||
|
];
|
||||||
|
|
||||||
|
const VALUES = [ true, 'jacogr' ];
|
||||||
|
const CALLDATA = `
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000001
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000040
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000006
|
||||||
|
6a61636f67720000000000000000000000000000000000000000000000000000
|
||||||
|
`.replace(/\s/g, '');
|
||||||
|
const SIGNATURE = '02356205';
|
||||||
|
|
||||||
|
const ENCODED = `0x${SIGNATURE}${CALLDATA}`;
|
||||||
|
|
||||||
const RETURN1 = '0000000000000000000000000000000000000000000000000000000000123456';
|
const RETURN1 = '0000000000000000000000000000000000000000000000000000000000123456';
|
||||||
const RETURN2 = '0000000000000000000000000000000000000000000000000000000000456789';
|
const RETURN2 = '0000000000000000000000000000000000000000000000000000000000456789';
|
||||||
let scope;
|
let scope;
|
||||||
@ -230,6 +261,33 @@ describe('api/contract/Contract', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('deploy without parameters', () => {
|
||||||
|
const contract = new Contract(eth, ABI_NO_PARAMS);
|
||||||
|
const CODE = '0x123';
|
||||||
|
const ADDRESS = '0xD337e80eEdBdf86eDBba021797d7e4e00Bb78351';
|
||||||
|
const RECEIPT_DONE = { contractAddress: ADDRESS.toLowerCase(), gasUsed: 50, blockNumber: 2500 };
|
||||||
|
|
||||||
|
let scope;
|
||||||
|
|
||||||
|
describe('success', () => {
|
||||||
|
before(() => {
|
||||||
|
scope = mockHttp([
|
||||||
|
{ method: 'eth_estimateGas', reply: { result: 1000 } },
|
||||||
|
{ method: 'parity_postTransaction', reply: { result: '0x678' } },
|
||||||
|
{ method: 'parity_checkRequest', reply: { result: '0x890' } },
|
||||||
|
{ method: 'eth_getTransactionReceipt', reply: { result: RECEIPT_DONE } },
|
||||||
|
{ method: 'eth_getCode', reply: { result: CODE } }
|
||||||
|
]);
|
||||||
|
|
||||||
|
return contract.deploy({ data: CODE }, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes the options through to postTransaction (incl. gas calculation)', () => {
|
||||||
|
expect(scope.body.parity_postTransaction.params[0].data).to.equal(CODE);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('deploy', () => {
|
describe('deploy', () => {
|
||||||
const contract = new Contract(eth, ABI);
|
const contract = new Contract(eth, ABI);
|
||||||
const ADDRESS = '0xD337e80eEdBdf86eDBba021797d7e4e00Bb78351';
|
const ADDRESS = '0xD337e80eEdBdf86eDBba021797d7e4e00Bb78351';
|
||||||
@ -252,7 +310,7 @@ describe('api/contract/Contract', () => {
|
|||||||
{ method: 'eth_getCode', reply: { result: '0x456' } }
|
{ method: 'eth_getCode', reply: { result: '0x456' } }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return contract.deploy({ data: '0x123' }, []);
|
return contract.deploy({ data: '0x123' }, VALUES);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('calls estimateGas, postTransaction, checkRequest, getTransactionReceipt & getCode in order', () => {
|
it('calls estimateGas, postTransaction, checkRequest, getTransactionReceipt & getCode in order', () => {
|
||||||
@ -261,7 +319,7 @@ describe('api/contract/Contract', () => {
|
|||||||
|
|
||||||
it('passes the options through to postTransaction (incl. gas calculation)', () => {
|
it('passes the options through to postTransaction (incl. gas calculation)', () => {
|
||||||
expect(scope.body.parity_postTransaction.params).to.deep.equal([
|
expect(scope.body.parity_postTransaction.params).to.deep.equal([
|
||||||
{ data: '0x123', gas: '0x4b0' }
|
{ data: `0x123${CALLDATA}`, gas: '0x4b0' }
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -280,7 +338,7 @@ describe('api/contract/Contract', () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return contract
|
return contract
|
||||||
.deploy({ data: '0x123' }, [])
|
.deploy({ data: '0x123' }, VALUES)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
expect(error.message).to.match(/not deployed, gasUsed/);
|
expect(error.message).to.match(/not deployed, gasUsed/);
|
||||||
});
|
});
|
||||||
@ -296,7 +354,7 @@ describe('api/contract/Contract', () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return contract
|
return contract
|
||||||
.deploy({ data: '0x123' }, [])
|
.deploy({ data: '0x123' }, VALUES)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
expect(error.message).to.match(/not deployed, getCode/);
|
expect(error.message).to.match(/not deployed, getCode/);
|
||||||
});
|
});
|
||||||
|
@ -458,23 +458,65 @@ class WriteContract extends Component {
|
|||||||
const { bytecode } = contract;
|
const { bytecode } = contract;
|
||||||
const abi = contract.interface;
|
const abi = contract.interface;
|
||||||
|
|
||||||
|
const metadata = contract.metadata
|
||||||
|
? (
|
||||||
|
<Input
|
||||||
|
allowCopy
|
||||||
|
label='Metadata'
|
||||||
|
readOnly
|
||||||
|
value={ contract.metadata }
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Input
|
<Input
|
||||||
|
allowCopy
|
||||||
|
label='ABI Interface'
|
||||||
readOnly
|
readOnly
|
||||||
value={ abi }
|
value={ abi }
|
||||||
label='ABI Interface'
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
|
allowCopy
|
||||||
|
label='Bytecode'
|
||||||
readOnly
|
readOnly
|
||||||
value={ `0x${bytecode}` }
|
value={ `0x${bytecode}` }
|
||||||
label='Bytecode'
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{ metadata }
|
||||||
|
{ this.renderSwarmHash(contract) }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderSwarmHash (contract) {
|
||||||
|
if (!contract || !contract.metadata) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { bytecode } = contract;
|
||||||
|
|
||||||
|
// @see https://solidity.readthedocs.io/en/develop/miscellaneous.html#encoding-of-the-metadata-hash-in-the-bytecode
|
||||||
|
const hashRegex = /a165627a7a72305820([a-f0-9]{64})0029$/;
|
||||||
|
|
||||||
|
if (!hashRegex.test(bytecode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = hashRegex.exec(bytecode)[1];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
allowCopy
|
||||||
|
label='Swarm Metadata Hash'
|
||||||
|
readOnly
|
||||||
|
value={ `${hash}` }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
renderErrors () {
|
renderErrors () {
|
||||||
const { annotations } = this.store;
|
const { annotations } = this.store;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user