Skip to content

Commit

Permalink
Tables work.
Browse files Browse the repository at this point in the history
  • Loading branch information
thekevinbrown committed Apr 16, 2019
1 parent 4e207be commit ccd4db7
Show file tree
Hide file tree
Showing 10 changed files with 299 additions and 1,209 deletions.
1,291 changes: 157 additions & 1,134 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@
"devDependencies": {
"@types/mkdirp": "0.5.2",
"@types/mocha": "5.2.6",
"@types/node": "11.13.0",
"@types/node-fetch": "2.3.0",
"@types/node": "^11.13.4",
"@types/node-fetch": "^2.3.2",
"@types/rimraf": "2.0.2",
"@types/text-encoding": "0.0.35",
"eosjs": "20.0.0",
"eosjs-ecc": "4.0.4",
"typescript": "3.4.1"
"typescript": "3.4.3"
},
"dependencies": {
"axios": "0.18.0",
"commander": "2.20.0",
"docker-cli-js": "2.5.2",
"glob": "7.1.3",
"mkdirp": "0.5.1",
"mocha": "6.0.2",
"mocha": "6.1.3",
"node-fetch": "2.3.0",
"qrcode-terminal": "0.12.0",
"rimraf": "2.6.3",
Expand Down
6 changes: 3 additions & 3 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ program
.allowUnknownOption(false)
.version(packageConfig.version)
.description(packageConfig.description)
.command('build', 'build all smart contracts')
.command('start eos', 'start the eos blockchain in docker')
.command('stop eos', 'stop the eos blockchain in docker')
.command('build [contract_path]', 'build all smart contracts')
.command('start', 'start the eos blockchain in docker')
.command('stop', 'stop the eos blockchain in docker')
.command('test', 'run your unit / integration tests')
.on('*', () => {
console.log('Unknown Command: ' + program.args.join(' '));
Expand Down
91 changes: 52 additions & 39 deletions src/contracts/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { nextBlock } from '../utils';
import { Api } from 'eosjs';
import { Contract as EOSJSContract, Type } from 'eosjs/dist/eosjs-serialize';
import { EOSManager } from '../eosManager';
import { Abi } from 'eosjs/dist/eosjs-rpc-interfaces';

export interface ContractActionParameters {
[key: string]: any;
Expand All @@ -23,10 +24,15 @@ export class Contract implements EOSJSContract {
return this._account;
}

public get identifier(): string {
return this._identifier;
}

constructor(
eos: Api,
identifier: string,
account: Account,
abi: Abi,
actions: Map<string, Type>,
types: Map<string, Type>
) {
Expand All @@ -36,49 +42,56 @@ export class Contract implements EOSJSContract {
this.actions = actions;
this.types = types;

// Set up all the actions as methods on the contract.
for (const action of actions.values()) {
if (action.fields.length > 0) {
(this as any)[action.name] = function(
params: ContractActionParameters,
options?: ContractActionOptions
) {
let authorization = (options && options.from) || account;
(this as any)[action.name] = function() {
const data: { [key: string]: any } = {};

return EOSManager.transact(
{
actions: [
{
account: account.name,
name: action.name,
authorization: authorization.active,
data: {
...params,
},
},
],
},
eos
// Copy the params across for the call.
if (
arguments.length != action.fields.length &&
arguments.length + 1 != action.fields.length
) {
throw new Error(
`Insufficient arguments supplied to ${action.name}. Expected ${
action.fields.length
} got ${arguments.length}.`
);
};
} else {
(this as any)[action.name] = function(options?: ContractActionOptions) {
let authorization = (options && options.from) || account;
}

return EOSManager.transact(
{
actions: [
{
account: account.name,
name: action.name,
authorization: authorization.active,
data: {},
},
],
},
eos
);
};
}
for (let i = 0; i < action.fields.length; i++) {
data[action.fields[i].name] = arguments[i];
}

// Who are we acting as?
// We default to sending transactions from the contract account.
let authorization = account;

if (arguments[action.fields.length] instanceof Account) {
authorization = arguments[action.fields.length];
}

return EOSManager.transact(
{
actions: [
{
account: account.name,
name: action.name,
authorization: authorization.active,
data,
},
],
},
eos
);
};
}

// And now the tables.
for (const table of abi.tables) {
(this as any)[table.name] = function() {
return this.getTableRows(table.name, arguments[0]);
};
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/contracts/contractDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class ContractDeployer {

const { actions, types } = await EOSManager.api.getContract(account.name);

return new Contract(EOSManager.api, contractIdentifier, account, actions, types) as T;
return new Contract(EOSManager.api, contractIdentifier, account, abi, actions, types) as T;
}

public static async deployClean<T extends Contract>(contractIdentifier: string) {
Expand Down
1 change: 1 addition & 0 deletions src/contracts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './contract';
export * from './contractDeployer';
export * from './tableRowsResult';
export * from './typeGenerator';
4 changes: 4 additions & 0 deletions src/contracts/tableRowsResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface TableRowsResult<T> {
rows: Array<T>;
more: boolean;
}
55 changes: 27 additions & 28 deletions src/contracts/typeGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const generateTypes = async (contractIdentifier: string) => {
'// Any changes you make will be overwritten by Lamington',
'// =====================================================',
'',
`import { Account, Contract } from 'lamington';`,
`import { Account, Contract, TableRowsResult } from 'lamington';`,
'',
];

Expand All @@ -70,40 +70,39 @@ export const generateTypes = async (contractIdentifier: string) => {
};

result.push(tableInterface);
}

// Generate the types of the function arguments for each function.
for (const action of contractActions) {
if (contractStructs[action.name].fields.length > 0) {
const paramInterface = {
[`export interface ${pascalCase(contractName)}${pascalCase(
action.name
)}Params`]: contractStructs[action.name].fields.map(
(parameter: any) => `${parameter.name}: ${mapParameterType(parameter.type)}`
),
};

result.push(paramInterface);
result.push('');
}
result.push('');
}

// Generate contract type from ABI
const generatedContractActions = contractActions.map((action: any) => {
// With a function for each action
const parameters = contractStructs[action.name].fields.map(
(parameter: any) => `${parameter.name}: ${mapParameterType(parameter.type)}`
);

// Optional parameter at the end on every contract method.
parameters.push('options?: { from?: Account }');

return `${action.name}(${parameters.join(', ')}): Promise<any>;`;
});

const generatedTables = contractTables.map(
(table: any) =>
`${table.name}(scope?: string): Promise<TableRowsResult<${pascalCase(
contractName
)}${pascalCase(table.name)}>>`
);

const contractInterface = {
[`export interface ${pascalCase(contractName)} extends Contract`]: contractActions.map(
(action: any) => {
if (contractStructs[action.name].fields.length > 0) {
return `${action.name}(params: ${pascalCase(contractName)}${pascalCase(
action.name
)}Params, options?: { from?: Account }): Promise<any>`;
} else {
return `${action.name}(options?: { from?: Account }): Promise<any>`;
}
}
),
[`export interface ${pascalCase(contractName)} extends Contract`]: [
...generatedContractActions,
'',
...generatedTables,
],
};

result.push(contractInterface);
result.push('');

await saveInterface(contractIdentifier, result);
};
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './accounts';
export * from './contracts';
export * from './utils';

import * as cliUtils from './cli/utils';
export const CLI = cliUtils;
49 changes: 49 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { EOSManager } from './eosManager';
import { TableRowsResult } from './contracts';
import assert = require('assert');

export const untilBlockNumber = async (number: number) => {
let { head_block_num } = await EOSManager.rpc.get_info();
Expand All @@ -15,3 +17,50 @@ export const sleep = async (delayInMs: number) =>
new Promise(resolve => setTimeout(resolve, delayInMs));

export const nextBlock = () => sleep(500);

export const assertRowsEqual = async <RowType>(
getTableRowsResult: Promise<TableRowsResult<RowType>>,
expected: Array<RowType>
) => {
const result = await getTableRowsResult;
assert.deepEqual(result, {
rows: expected,
more: false,
});
};

export const assertRowCount = async (
getTableRowsResult: Promise<TableRowsResult<any>>,
expectedRowCount: number
) => {
const result = await getTableRowsResult;

assert.equal(
result.more,
false,
`There were more rows pending on the response which was not expected.`
);

assert.equal(result.rows.length, expectedRowCount, `Different number of rows than expected.`);
};

export const assertEOSError = async (
operation: Promise<any>,
eosErrorText: string,
description: string
) => {
try {
await operation;
} catch (error) {
const expectedError = error.search(eosErrorText) >= 0;
assert(expectedError, `Expected ${description}, got '${error}' instead`);
return;
}
assert.fail(`Expected ${description} but operation completed successfully.`);
};

export const assertEOSAssert = (operation: Promise<any>) =>
assertEOSError(operation, 'eosio_assert_message_exception', 'assert');

export const assertMissingAuthority = (operation: Promise<any>) =>
assertEOSError(operation, 'missing_auth_exception', 'missing authority');

0 comments on commit ccd4db7

Please sign in to comment.