diff --git a/packages/api/test/data/incrementer-opt.wasm b/packages/api/test/data/incrementer-opt.wasm new file mode 100644 index 0000000000..2d85f68983 Binary files /dev/null and b/packages/api/test/data/incrementer-opt.wasm differ diff --git a/packages/api/test/data/incrementer.json b/packages/api/test/data/incrementer.json new file mode 100644 index 0000000000..732288243f --- /dev/null +++ b/packages/api/test/data/incrementer.json @@ -0,0 +1,44 @@ +{ + "name": "Incrementer", + "deploy": { + "args": [ + { + "name": "init_value", + "type": "u32" + } + ] + }, + "messages": [ + { + "name": "inc", + "selector": 257544423, + "mutates": true, + "args": [ + { + "name": "by", + "type": "u32" + } + ], + "return_type": null + }, + { + "name": "get", + "selector": 4266279973, + "mutates": false, + "args": [], + "return_type": "u32" + }, + { + "name": "compare", + "selector": 363906316, + "mutates": false, + "args": [ + { + "name": "with", + "type": "u32" + } + ], + "return_type": "bool" + } + ] +} \ No newline at end of file diff --git a/packages/api/test/e2e/promise-contract.spec.js b/packages/api/test/e2e/promise-contract.spec.js index e7a9b7eb01..0f28eb1041 100644 --- a/packages/api/test/e2e/promise-contract.spec.js +++ b/packages/api/test/e2e/promise-contract.spec.js @@ -8,21 +8,20 @@ import path from 'path'; import { ContractAbi } from '@plugnet/types'; import testingPairs from '@plugnet/keyring/testingPairs'; -import json from '../data/erc20.json'; +import incrementer from '../data/incrementer.json'; +import erc20 from '../data/erc20.json'; import Api from '../../src/promise'; describe.skip('e2e contracts', () => { let address; let codeHash; let keyring; - let abi; let api; beforeEach(async (done) => { if (!api) { api = await Api.create(); - abi = new ContractAbi(json); keyring = testingPairs({ type: 'sr25519' }); } @@ -30,63 +29,79 @@ describe.skip('e2e contracts', () => { done(); }); - it('has the attached methods', () => { - expect(Object.keys(abi.messages)).toEqual( - ['totalSupply', 'balanceOf', 'allowance', 'transfer', 'approve', 'transferFrom'] - ); - }); + describe('incrementer', () => { + let abi; - it('allows putCode', (done) => { - const code = fs.readFileSync(path.join(__dirname, '../data/erc20.wasm')).toString('hex'); + beforeAll(() => { + abi = new ContractAbi(incrementer); + }); - api.tx.contract - .putCode(200000, `0x${code}`) - .signAndSend(keyring.eve, (result) => { - console.error('putCode', JSON.stringify(result)); + it('allows putCode', (done) => { + const code = fs.readFileSync(path.join(__dirname, '../data/incrementer-opt.wasm')).toString('hex'); - if (result.status.isFinalized) { - const record = result.findRecord('contract', 'CodeStored'); + api.tx.contract + .putCode(200000, `0x${code}`) + .signAndSend(keyring.eve, (result) => { + console.error('putCode', JSON.stringify(result)); - if (record) { - codeHash = record.event.data[0]; + if (result.status.isFinalized) { + const record = result.findRecord('contract', 'CodeStored'); + if (record) { + codeHash = record.event.data[0]; + + done(); + } + } + }); + }); + + it('allows contract create', (done) => { + expect(codeHash).toBeDefined(); + + api.tx.contract + .create(12345, 500000, codeHash, abi.deploy(12345)) + .signAndSend(keyring.bob, (result) => { + console.error('create', JSON.stringify(result)); + + if (result.status.isFinalized) { + const record = result.findRecord('contract', 'Instantiated'); + + if (record) { + address = record.event.data[1]; + + done(); + } + } + }); + }); + + it('allows contract call', (done) => { + expect(address).toBeDefined(); + + api.tx.contract + .call(address, 12345, 500000, abi.messages.inc(123)) + .signAndSend(keyring.bob, (result) => { + console.error('call', JSON.stringify(result)); + + if (result.status.isFinalized && result.findRecord('system', 'ExtrinsicSuccess')) { done(); } - } - }); + }); + }); }); - it('allows contract create', (done) => { - expect(codeHash).toBeDefined(); + describe('erc20', () => { + let abi; - api.tx.contract - .create(1234, 12345, codeHash, abi.deploy(12345)) - .signAndSend(keyring.bob, (result) => { - console.error('create', JSON.stringify(result)); + beforeAll(() => { + abi = abi = new ContractAbi(erc20); + }); - if (result.status.isFinalized) { - const record = result.findRecord('contract', 'Instantiated'); - - if (record) { - address = record.event.data[1]; - - done(); - } - } - }); - }); - - it('allows contract call', (done) => { - expect(address).toBeDefined(); - - api.tx.contract - .call(address, 123, 12345, abi.messages.balanceOf(keyring.alice.address())) - .signAndSend(keyring.bob, (result) => { - console.error('call', JSON.stringify(result)); - - if (result.status.isFinalized && result.findRecord('system', 'ExtrinsicSuccess')) { - done(); - } - }); + it('has the attached methods', () => { + expect(Object.keys(abi.messages)).toEqual( + ['totalSupply', 'balanceOf', 'allowance', 'transfer', 'approve', 'transferFrom'] + ); + }); }); }); diff --git a/packages/types/src/ContractAbi.ts b/packages/types/src/ContractAbi.ts index cce5c187f8..4ed7f36987 100644 --- a/packages/types/src/ContractAbi.ts +++ b/packages/types/src/ContractAbi.ts @@ -4,7 +4,7 @@ import { CodecArg, Constructor } from './types'; -import { assert, isNumber, isNull, isString, isUndefined, stringCamelCase } from '@plugnet/util'; +import { assert, isNumber, isNull, isString, isUndefined, stringCamelCase, u8aToHex } from '@plugnet/util'; import Compact from './codec/Compact'; import { createClass } from './codec/createType'; @@ -104,14 +104,14 @@ export default class ContractAbi implements Contract { }); } - private _createClazz (args: ContractABIArgs, isDeploy: boolean): Constructor { + private _createClazz (args: ContractABIArgs, baseDef: { [index: string]: string }): Constructor { return createClass( JSON.stringify( args.reduce((base: { [index: string]: string }, { name, type }) => { base[name] = type; return base; - }, isDeploy ? {} : { __selector: 'u32' }) + }, baseDef) ) ); } @@ -121,20 +121,22 @@ export default class ContractAbi implements Contract { name: stringCamelCase(name), type })); - const Clazz = this._createClazz(args, isUndefined(method.selector)); - const base: { [index: string]: any } = { __selector: method.selector }; + const Clazz = this._createClazz(args, isUndefined(method.selector) ? {} : { __selector: 'u32' }); + const baseStruct: { [index: string]: any } = { __selector: method.selector }; const encoder = (...params: Array): Uint8Array => { assert(params.length === args.length, `Expected ${args.length} arguments to contract ${name}, found ${params.length}`); - return Compact.addLengthPrefix( - new Clazz( - args.reduce((mapped, { name }, index) => { - mapped[name] = params[index]; + const u8a = new Clazz( + args.reduce((mapped, { name }, index) => { + mapped[name] = params[index]; - return mapped; - }, { ...base }) - ).toU8a() - ); + return mapped; + }, { ...baseStruct }) + ).toU8a(); + + console.error('hexToU8a(encoded)', u8aToHex(u8a)); + + return Compact.addLengthPrefix(u8a); }; const fn = (encoder as ContractABIFn);