diff --git a/src/contract.ts b/src/contract.ts index ba1801e..c9df4d7 100644 --- a/src/contract.ts +++ b/src/contract.ts @@ -94,31 +94,29 @@ export class Contract { return this.actionNames.includes(String(name)) } - public action(name): ActionConstructor { + public action(name, data: ActionDataType, options?: ActionOptions): Action { if (!this.hasAction(name)) { throw new Error(`Contract (${this.account}) does not have an action named (${name})`) } - return (data: ActionDataType, options?: ActionOptions) => { - let authorization = [PlaceholderAuth] - if (options && options.authorization) { - authorization = options.authorization.map((auth) => PermissionLevel.from(auth)) - } - return Action.from( - { - account: this.account, - name, - authorization, - data, - }, - this.abi - ) + let authorization = [PlaceholderAuth] + if (options && options.authorization) { + authorization = options.authorization.map((auth) => PermissionLevel.from(auth)) } + return Action.from( + { + account: this.account, + name, + authorization, + data, + }, + this.abi + ) } public actions(actions: ActionsArgs[], options?: ActionOptions): Action[] { return actions.map((action) => - this.action(action.name)(action.data, { + this.action(action.name, action.data, { authorization: action.authorization || options?.authorization, }) ) diff --git a/test/data/contracts/mock-rewards.ts b/test/data/contracts/mock-rewards.ts index 38690e8..2570044 100644 --- a/test/data/contracts/mock-rewards.ts +++ b/test/data/contracts/mock-rewards.ts @@ -1,39 +1,17 @@ -import { - ActionOptions, - Contract as BaseContract, - ContractArgs, - PartialBy, - blobStringToAbi, -} from '@wharfkit/contract' +import {ActionOptions, Contract as BaseContract, ContractArgs, PartialBy} from '@wharfkit/contract' import { ABI, Action, - APIClient, - Session, - Struct, - TransactResult, Asset, - Checksum256, + AssetType, + Blob, Float64, Name, + NameType, + Struct, TimePoint, - TimePointSec, - UInt128, UInt16, - UInt32, - UInt64, - UInt8, - AssetType, - Blob, - Checksum256Type, - Float64Type, - NameType, - TimePointType, - UInt128Type, UInt16Type, - UInt32Type, - UInt64Type, - UInt8Type, } from '@wharfkit/session' export namespace RewardsGm { export const abiBlob = Blob.from( @@ -48,19 +26,17 @@ export namespace RewardsGm { account: Name.from('rewards.gm'), }) } - action( - name: T - ): (data: ActionNameParams[T], options?: ActionOptions) => Action { - return (data, options) => super.action(name)(data, options) + action( + name: T, + data: ActionNameParams[T], + options?: ActionOptions + ): Action { + return super.action(name, data, options) + } + table(name: T) { + return super.table(name, TableMap[name]) } } - export type ActionNames = - | 'adduser' - | 'claim' - | 'configure' - | 'deluser' - | 'receipt' - | 'updateuser' export interface ActionNameParams { adduser: ActionParams.Adduser claim: ActionParams.Claim @@ -76,20 +52,24 @@ export namespace RewardsGm { } export interface Claim { account: NameType - amount: AssetType + amount?: AssetType } export interface Configure { token_symbol: Symbol oracle_account: NameType - oracle_pairs: Types.Oracle_pair[] + oracle_pairs: Types.OraclePair[] } export interface Deluser { account: NameType } + export interface OraclePair { + name: NameType + precision: UInt16Type + } export interface Receipt { account: NameType amount: AssetType - ticker: Types.Price_info[] + ticker: Types.PriceInfo[] } export interface Updateuser { account: NameType @@ -99,81 +79,63 @@ export namespace RewardsGm { export namespace Types { @Struct.type('adduser') export class Adduser extends Struct { - @Struct.field('name') - declare account: Name - @Struct.field('uint16') - declare weight: UInt16 + @Struct.field(Name) account!: Name + @Struct.field(UInt16) weight!: UInt16 } @Struct.type('claim') export class Claim extends Struct { - @Struct.field('name') - declare account: Name - @Struct.field('asset?') - declare amount: Asset + @Struct.field(Name) account!: Name + @Struct.field(Asset, {optional: true}) amount?: Asset + } + @Struct.type('oracle_pair') + export class OraclePair extends Struct { + @Struct.field(Name) name!: Name + @Struct.field(UInt16) precision!: UInt16 } @Struct.type('config') export class Config extends Struct { - @Struct.field('symbol') - declare token_symbol: Symbol - @Struct.field('name') - declare oracle_account: Name - @Struct.field('oracle_pair[]') - declare oracle_pairs: RewardsGm.Types.Oracle_pair + @Struct.field(Asset.Symbol) token_symbol!: Asset.Symbol + @Struct.field(Name) oracle_account!: Name + @Struct.field(OraclePair, {array: true}) oracle_pairs!: OraclePair[] } @Struct.type('configure') export class Configure extends Struct { - @Struct.field('symbol') - declare token_symbol: Symbol - @Struct.field('name') - declare oracle_account: Name - @Struct.field('oracle_pair[]') - declare oracle_pairs: RewardsGm.Types.Oracle_pair + @Struct.field(Asset.Symbol) token_symbol!: Asset.Symbol + @Struct.field(Name) oracle_account!: Name + @Struct.field(OraclePair, {array: true}) oracle_pairs!: OraclePair[] } @Struct.type('deluser') export class Deluser extends Struct { - @Struct.field('name') - declare account: Name - } - @Struct.type('oracle_pair') - export class Oracle_pair extends Struct { - @Struct.field('name') - declare name: Name - @Struct.field('uint16') - declare precision: UInt16 + @Struct.field(Name) account!: Name } @Struct.type('price_info') - export class Price_info extends Struct { - @Struct.field('string') - declare pair: String - @Struct.field('float64') - declare price: Float64 - @Struct.field('time_point') - declare timestamp: TimePoint + export class PriceInfo extends Struct { + @Struct.field('string') pair!: string + @Struct.field(Float64) price!: Float64 + @Struct.field(TimePoint) timestamp!: TimePoint } @Struct.type('receipt') export class Receipt extends Struct { - @Struct.field('name') - declare account: Name - @Struct.field('asset') - declare amount: Asset - @Struct.field('price_info[]') - declare ticker: RewardsGm.Types.Price_info + @Struct.field(Name) account!: Name + @Struct.field(Asset) amount!: Asset + @Struct.field(PriceInfo, {array: true}) ticker!: PriceInfo[] } @Struct.type('updateuser') export class Updateuser extends Struct { - @Struct.field('name') - declare account: Name - @Struct.field('uint16') - declare weight: UInt16 + @Struct.field(Name) account!: Name + @Struct.field(UInt16) weight!: UInt16 } @Struct.type('user_row') - export class User_row extends Struct { - @Struct.field('name') - declare account: Name - @Struct.field('uint16') - declare weight: UInt16 - @Struct.field('asset') - declare balance: Asset + export class UserRow extends Struct { + @Struct.field(Name) account!: Name + @Struct.field(UInt16) weight!: UInt16 + @Struct.field(Asset) balance!: Asset } } + const TableMap = { + config: Types.Config, + users: Types.UserRow, + } } + +export default RewardsGm diff --git a/test/data/requests/00aac80526ae03d5cfe8c7e4f4ae1c0d2b916049.json b/test/data/requests/00aac80526ae03d5cfe8c7e4f4ae1c0d2b916049.json new file mode 100644 index 0000000..a60c980 --- /dev/null +++ b/test/data/requests/00aac80526ae03d5cfe8c7e4f4ae1c0d2b916049.json @@ -0,0 +1,18 @@ +{ + "request": { + "path": "https://eos.greymass.com/v1/chain/get_table_rows", + "params": { + "method": "POST", + "body": "{\"table\":\"users\",\"code\":\"rewards.gm\",\"scope\":\"rewards.gm\",\"limit\":1,\"index_position\":\"primary\",\"key_type\":\"name\",\"json\":false}" + } + }, + "status": 200, + "json": { + "rows": [ + "0000900ca04b6b35f401000000000000000004454f5300000000" + ], + "more": true, + "next_key": "4352878718026951040" + }, + "text": "{\"rows\":[\"0000900ca04b6b35f401000000000000000004454f5300000000\"],\"more\":true,\"next_key\":\"4352878718026951040\"}" +} \ No newline at end of file diff --git a/test/data/requests/0d9424766a10f0330866036588971c5779697dfa.json b/test/data/requests/0d9424766a10f0330866036588971c5779697dfa.json new file mode 100644 index 0000000..9b4130a --- /dev/null +++ b/test/data/requests/0d9424766a10f0330866036588971c5779697dfa.json @@ -0,0 +1,18 @@ +{ + "request": { + "path": "https://eos.greymass.com/v1/chain/get_table_rows", + "params": { + "method": "POST", + "body": "{\"json\":false,\"limit\":1,\"table\":\"config\",\"code\":\"rewards.gm\",\"scope\":\"rewards.gm\",\"key_type\":\"name\"}" + } + }, + "status": 200, + "json": { + "rows": [ + "04454f5300000000a0223297ba56a34a010000000024ac31550400" + ], + "more": false, + "next_key": "" + }, + "text": "{\"rows\":[\"04454f5300000000a0223297ba56a34a010000000024ac31550400\"],\"more\":false,\"next_key\":\"\"}" +} \ No newline at end of file diff --git a/test/data/requests/742c0f31283ca71045d23ddf3ce8418f87d4c474.json b/test/data/requests/742c0f31283ca71045d23ddf3ce8418f87d4c474.json new file mode 100644 index 0000000..84b229a --- /dev/null +++ b/test/data/requests/742c0f31283ca71045d23ddf3ce8418f87d4c474.json @@ -0,0 +1,18 @@ +{ + "request": { + "path": "https://eos.greymass.com/v1/chain/get_table_rows", + "params": { + "method": "POST", + "body": "{\"table\":\"config\",\"code\":\"rewards.gm\",\"scope\":\"rewards.gm\",\"limit\":1,\"index_position\":\"primary\",\"key_type\":\"name\",\"json\":false}" + } + }, + "status": 200, + "json": { + "rows": [ + "04454f5300000000a0223297ba56a34a010000000024ac31550400" + ], + "more": false, + "next_key": "" + }, + "text": "{\"rows\":[\"04454f5300000000a0223297ba56a34a010000000024ac31550400\"],\"more\":false,\"next_key\":\"\"}" +} \ No newline at end of file diff --git a/test/tests/codegen.ts b/test/tests/codegen.ts index cd0f026..c3726ac 100644 --- a/test/tests/codegen.ts +++ b/test/tests/codegen.ts @@ -1,7 +1,7 @@ -import {assert} from 'chai' -import fs from 'fs' import {ABI, APIClient, Name} from '@wharfkit/antelope' import {makeClient} from '@wharfkit/mock-data' +import {assert} from 'chai' +import fs from 'fs' import {Contract} from 'src/contract' import * as MockRewardsGm from '$test/data/contracts/mock-rewards' @@ -11,7 +11,7 @@ import {runGenericContractTests} from './contract' const GeneratedRewardsGm = await generateCodegenContract('rewards.gm') const contracts = { MockRewardsGm, - GeneratedRewardsGm, + GeneratedRewardsGm: GeneratedRewardsGm.import, } const files = { diff --git a/test/tests/contract.ts b/test/tests/contract.ts index 86459b6..16c1fd7 100644 --- a/test/tests/contract.ts +++ b/test/tests/contract.ts @@ -128,19 +128,19 @@ export function runGenericContractTests(contract: Contract) { test('load action using Name', function () { const actionName = Name.from(contract.actionNames[0]) const params = getMockParams(contract) - const action = contract.action(actionName)(params) + const action = contract.action(actionName, params) assert.instanceOf(action, Action) assert.isTrue(action.name.equals(actionName)) }) test('load action using string', function () { const actionName = contract.actionNames[0] const params = getMockParams(contract) - const action = contract.action(actionName)(params) + const action = contract.action(actionName, params) assert.instanceOf(action, Action) assert.isTrue(action.name.equals(actionName)) }) test('throws on invalid name', function () { - assert.throws(() => contract.action('foo')({})) + assert.throws(() => contract.action('foo', {})) }) }) } @@ -304,7 +304,7 @@ export function runGenericContractTests(contract: Contract) { suite('action', function () { suite('load', function () { test('using Name', function () { - const action = tokenContract.action(Name.from('transfer'))(transferData) + const action = tokenContract.action(Name.from('transfer'), transferData) assert.instanceOf(action, Action) assert.isTrue(action.account.equals('eosio.token')) assert.isTrue(action.name.equals('transfer')) @@ -322,20 +322,20 @@ export function runGenericContractTests(contract: Contract) { assert.isTrue(action.data.equals(encoded)) }) test('using string', function () { - const action = tokenContract.action('transfer')(transferData) + const action = tokenContract.action('transfer', transferData) assert.instanceOf(action, Action) assert.isTrue(action.account.equals('eosio.token')) assert.isTrue(action.name.equals('transfer')) }) test('defaults to placeholders', function () { - const action = tokenContract.action('transfer')(transferData) + const action = tokenContract.action('transfer', transferData) assert.isTrue(action.authorization[0].equals(PlaceholderAuth)) }) }) suite('throws', function () { test('with incomplete action data', async function () { assert.throws(() => - tokenContract.action('transfer')({ + tokenContract.action('transfer', { from: 'foo', to: 'bar', quantity: '1.0000 EOS', @@ -344,19 +344,19 @@ export function runGenericContractTests(contract: Contract) { }) test('with invalid action data', async function () { assert.throws(() => - tokenContract.action('transfer')({ + tokenContract.action('transfer', { ...transferData, to: Asset.from('1.0000 EOS'), }) ) }) test('with invalid name', async function () { - assert.throws(() => tokenContract.action('foo')(transferData)) + assert.throws(() => tokenContract.action('foo', transferData)) }) }) suite('overrides', function () { test('authorization', async function () { - const action = tokenContract.action('transfer')(transferData, { + const action = tokenContract.action('transfer', transferData, { authorization: [ { actor: 'foo', @@ -405,4 +405,4 @@ export function runGenericContractTests(contract: Contract) { }) }) }) -})() +}) diff --git a/test/tests/mock.ts b/test/tests/mock.ts new file mode 100644 index 0000000..d6bc549 --- /dev/null +++ b/test/tests/mock.ts @@ -0,0 +1,90 @@ +import {assert} from 'chai' +import { + Action, + Asset, + Bytes, + Name, + PermissionLevel, + Serializer, + Struct, + UInt16, +} from '@wharfkit/antelope' +import {makeClient} from '@wharfkit/mock-data' + +import RewardsGm from '$test/data/contracts/mock-rewards' +import {PlaceholderName, PlaceholderPermission} from '@wharfkit/signing-request' +import {Table, TableCursor} from 'src/index-module' + +const client = makeClient('https://eos.greymass.com') +const contract = new RewardsGm.Contract({client}) + +suite('functionality', function () { + suite('Contract', function () { + suite('retrieve action', function () { + test('untyped', function () { + const action = contract.action('claim', { + account: PlaceholderName, + }) + assert.instanceOf(action, Action) + assert.instanceOf(action.account, Name) + assert.instanceOf(action.name, Name) + assert.instanceOf(action.authorization[0], PermissionLevel) + assert.instanceOf(action.data, Bytes) + assert.isTrue(action.account.equals('rewards.gm')) + assert.isTrue(action.name.equals('claim')) + assert.isTrue(action.authorization[0].actor.equals(PlaceholderName)) + assert.isTrue(action.authorization[0].permission.equals(PlaceholderPermission)) + + @Struct.type('claim') + class Claim extends Struct { + @Struct.field(Name) account!: Name + @Struct.field(Asset, {optional: true}) amount?: Asset + } + const decoded = Serializer.decode({ + data: action.data, + abi: contract.abi, + type: Claim, + }) + assert.isTrue(decoded.account.equals(PlaceholderName)) + assert.isNull(decoded.amount) + }) + test('typed values', function () { + const action = contract.action('claim', { + account: Name.from('teamgreymass'), + }) + assert.instanceOf(action, Action) + }) + test('struct', function () { + @Struct.type('claim') + class Claim extends Struct { + @Struct.field(Name) account!: Name + @Struct.field(Asset, {optional: true}) amount?: Asset + } + const action = contract.action( + 'claim', + Claim.from({ + account: Name.from('teamgreymass'), + }) + ) + assert.instanceOf(action, Action) + }) + }) + suite('retrieve table', function () { + test('automatically typed', async function () { + const table = contract.table('config') + assert.instanceOf(table, Table) + + const config = await table.get() + assert.instanceOf(config, RewardsGm.Types.Config) + + const cursor = await table.first(1) + assert.instanceOf(cursor, TableCursor) + const result = await cursor.next() + assert.instanceOf(result[0], RewardsGm.Types.Config) + + const user = await contract.table('users').get() + assert.instanceOf(user, RewardsGm.Types.UserRow) + }) + }) + }) +}) diff --git a/yarn.lock b/yarn.lock index 0f6c4ca..f31c51c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3169,6 +3169,11 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" +prettier-plugin-organize-imports@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.3.tgz#6b0141ac71f7ee9a673ce83e95456319e3a7cf0d" + integrity sha512-KFvk8C/zGyvUaE3RvxN2MhCLwzV6OBbFSkwZ2OamCrs9ZY4i5L77jQ/w4UmUr+lqX8qbaqVq6bZZkApn+IgJSg== + prettier@^2.2.1: version "2.7.1" resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz"