From 54fb057d63a6b31e38e7ba9c9cd4a9830e10ccb2 Mon Sep 17 00:00:00 2001 From: Aaron Cox Date: Tue, 16 Jan 2024 17:14:42 -0800 Subject: [PATCH] Generated code support for readonly transactions and return values (#31) * Initial testing.gm for return values * Failing test * Fixed contract name * Updated contract kit * The updated test * The changes we need added to code generation * chore: implementing return values codegen (#32) * chore: implementing return values codegen * enhancement: making data param on readonly method optional --------- Co-authored-by: Daniel Fugere --- Makefile | 1 + package.json | 2 +- src/commands/contract/class.ts | 80 +++ src/commands/contract/helpers.ts | 12 +- src/commands/contract/index.ts | 17 +- src/commands/contract/interfaces.ts | 39 +- src/commands/contract/structs.ts | 14 +- test/data/abis/testing.gm.json | 539 ++++++++++++++++++ test/data/contracts/mock-testing.gm.ts | 321 +++++++++++ ...fbae776e329473d0b26058142fbde12780727.json | 69 +++ test/tests/contract-codegen.ts | 5 + test/tests/contract-functionality.ts | 20 +- test/tests/helpers/generic.ts | 7 + yarn.lock | 12 +- 14 files changed, 1118 insertions(+), 20 deletions(-) create mode 100644 test/data/abis/testing.gm.json create mode 100644 test/data/contracts/mock-testing.gm.ts create mode 100644 test/data/requests/05ffbae776e329473d0b26058142fbde12780727.json diff --git a/Makefile b/Makefile index 843829c..5af30df 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,7 @@ update_mock_contracts: node_modules clean lib node lib/cli.js generate eosio.token -u https://jungle4.greymass.com -j test/data/abis/eosio.token.json -f test/data/contracts/mock-eosio.token.ts -e .eslintrc node lib/cli.js generate hegemon.hgm -u https://jungle4.greymass.com -j test/data/abis/hegemon.hgm.json -f test/data/contracts/mock-hegemon.hgm.ts -e .eslintrc node lib/cli.js generate rewards.gm -u https://jungle4.greymass.com -j test/data/abis/rewards.gm.json -f test/data/contracts/mock-rewards.gm.ts -e .eslintrc + node lib/cli.js generate testing.gm -u https://jungle4.greymass.com -j test/data/abis/testing.gm.json -f test/data/contracts/mock-testing.gm.ts -e .eslintrc .PHONY: check check: node_modules diff --git a/package.json b/package.json index 280bcbe..eba1833 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "@wharfkit/antelope": "^1.0.0", "@wharfkit/common": "^1.2.0", - "@wharfkit/contract": "^1.1.1", + "@wharfkit/contract": "^1.1.4", "commander": "^11.0.0", "eslint": "^8.48.0", "node-fetch": "^2.6.1", diff --git a/src/commands/contract/class.ts b/src/commands/contract/class.ts index cb28185..cf81e87 100644 --- a/src/commands/contract/class.ts +++ b/src/commands/contract/class.ts @@ -47,6 +47,11 @@ export async function generateContractClass(contractName: string, abi: ABI.Def) classMembers.push(actionMethod) } + if (abi.action_results.length) { + const readonlyMethod = generateReadonlyMethod() + classMembers.push(readonlyMethod) + } + if (abi.tables.length) { const tableMethod = generateTableMethod() @@ -168,6 +173,81 @@ function generateActionMethod(): ts.MethodDeclaration { ) } +function generateReadonlyMethod(): ts.MethodDeclaration { + // Create the generic type parameter 'T' with a constraint to 'ActionReturnNames' + const typeParameter = ts.factory.createTypeParameterDeclaration( + undefined, + 'T', + ts.factory.createTypeReferenceNode('ActionReturnNames') + ) + + // Create the function parameters. + const nameParameter = ts.factory.createParameterDeclaration( + undefined, + undefined, + 'name', + undefined, + ts.factory.createTypeReferenceNode('T'), + undefined + ) + + const dataParameter = ts.factory.createParameterDeclaration( + undefined, + undefined, + 'data', + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createIndexedAccessTypeNode( + ts.factory.createTypeReferenceNode('ActionNameParams'), + ts.factory.createTypeReferenceNode('T') + ), + undefined + ) + + // Generate the function body. + const methodBody = ts.factory.createBlock( + [ + ts.factory.createReturnStatement( + ts.factory.createAsExpression( + ts.factory.createAsExpression( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createSuper(), + 'readonly' + ), + undefined, + [ + ts.factory.createIdentifier('name'), + ts.factory.createIdentifier('data'), + ] + ), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword) + ), + ts.factory.createIndexedAccessTypeNode( + ts.factory.createTypeReferenceNode('ActionReturnValues'), + ts.factory.createTypeReferenceNode('T') + ) + ) + ), + ], + true + ) + + // Create the method declaration + return ts.factory.createMethodDeclaration( + undefined, + undefined, + 'readonly', + undefined, + [typeParameter], + [nameParameter, dataParameter], + ts.factory.createIndexedAccessTypeNode( + ts.factory.createTypeReferenceNode('ActionReturnValues'), + ts.factory.createTypeReferenceNode('T') + ), + methodBody + ) +} + export function generateTableMethod(): ts.MethodDeclaration { // Create the generic type parameter 'T' with a constraint to 'tables' const typeParameter = ts.factory.createTypeParameterDeclaration( diff --git a/src/commands/contract/helpers.ts b/src/commands/contract/helpers.ts index 860c48b..f2fd9f5 100644 --- a/src/commands/contract/helpers.ts +++ b/src/commands/contract/helpers.ts @@ -46,7 +46,7 @@ export function getCoreImports(abi: ABI.Def) { } } - if (abi.variants.length != 0) { + if (abi.variants.length) { coreImports.push('Variant') for (const variant of abi.variants) { variant.types.forEach((typeString) => { @@ -59,6 +59,16 @@ export function getCoreImports(abi: ABI.Def) { } } + if (abi.action_results.length) { + for (const actionResult of abi.action_results) { + const {type: abiType} = findAbiType(actionResult.result_type, abi) + const coreClass = findCoreClassImport(abiType) + if (coreClass) { + coreImports.push(coreClass) + } + } + } + return { classes: coreImports.filter((value, index, self) => self.indexOf(value) === index), types: coreTypes diff --git a/src/commands/contract/index.ts b/src/commands/contract/index.ts index 13b01e2..2fe98d9 100644 --- a/src/commands/contract/index.ts +++ b/src/commands/contract/index.ts @@ -9,11 +9,16 @@ import {abiToBlob, ContractKit} from '@wharfkit/contract' import {log, makeClient} from '../../utils' import {generateContractClass} from './class' import {generateImportStatement, getCoreImports} from './helpers' -import {generateActionNamesInterface, generateActionsNamespace} from './interfaces' +import { + generateActionNamesInterface, + generateActionReturnValuesInterface, + generateActionsNamespace, +} from './interfaces' import {generateTableMap, generateTableTypesInterface} from './maps' import {generateNamespace} from './namespace' import {generateStructClasses} from './structs' import {generateActionsTypeAlias, generateRowType, generateTablesTypeAlias} from './types' +import {generateActionReturnNamesType} from './interfaces' const printer = ts.createPrinter() @@ -161,6 +166,14 @@ export async function generateContract(contractName: string, abi: ABI, eslintrc? const actionsTypeAlias = generateActionsTypeAlias() const rowTypeAlias = generateRowType() + let actionResultValuesInterface: ts.InterfaceDeclaration | undefined + let actionResultsNamesType: ts.TypeAliasDeclaration | undefined + + if (abi.action_results.length) { + actionResultValuesInterface = generateActionReturnValuesInterface(abi) + actionResultsNamesType = generateActionReturnNamesType() + } + const sourceFile = ts.factory.createSourceFile( [ importAntelopeTypesStatement, @@ -178,6 +191,8 @@ export async function generateContract(contractName: string, abi: ABI, eslintrc? rowTypeAlias, actionsTypeAlias, tablesTypeAlias, + ...(actionResultValuesInterface ? [actionResultValuesInterface] : []), + ...(actionResultsNamesType ? [actionResultsNamesType] : []), ], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None diff --git a/src/commands/contract/interfaces.ts b/src/commands/contract/interfaces.ts index f9a798d..84b3728 100644 --- a/src/commands/contract/interfaces.ts +++ b/src/commands/contract/interfaces.ts @@ -1,7 +1,7 @@ import type {ABI} from '@wharfkit/antelope' import ts from 'typescript' import {parseType, removeCommas, removeDuplicateInterfaces} from './helpers' -import {getActionFieldFromAbi} from './structs' +import {findFieldTypeString, getActionFieldFromAbi} from './structs' import {findAbiStruct, findExternalType, findTypeFromAlias, findVariant} from './finders' export function generateActionNamesInterface(abi: ABI.Def): ts.InterfaceDeclaration { @@ -157,3 +157,40 @@ function findParamTypeString(typeString: string, namespace = '', abi: ABI.Def): return parseType(fieldType) } + +export function generateActionReturnValuesInterface(abi: ABI.Def): ts.InterfaceDeclaration { + const actionResults: ABI.ActionResult[] = abi.action_results + const members = actionResults.map((result) => { + return ts.factory.createPropertySignature( + undefined, + String(result.name), + undefined, + ts.factory.createTypeReferenceNode( + findFieldTypeString(result.result_type, 'Types.', abi), + undefined + ) + ) + }) + + return ts.factory.createInterfaceDeclaration( + undefined, + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + 'ActionReturnValues', + undefined, + undefined, + members + ) +} + +export function generateActionReturnNamesType(): ts.TypeAliasDeclaration { + return ts.factory.createTypeAliasDeclaration( + undefined, + [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)], + 'ActionReturnNames', + undefined, + ts.factory.createTypeOperatorNode( + ts.SyntaxKind.KeyOfKeyword, + ts.factory.createTypeReferenceNode('ActionReturnValues', undefined) + ) + ) +} diff --git a/src/commands/contract/structs.ts b/src/commands/contract/structs.ts index d16c091..d009c0c 100644 --- a/src/commands/contract/structs.ts +++ b/src/commands/contract/structs.ts @@ -101,9 +101,7 @@ export function generateVariant(variant, abi: any, isExport = false): ts.ClassDe ts.factory.createUnionTypeNode( variant.fields.map((field) => { return ts.factory.createTypeReferenceNode( - ts.factory.createIdentifier( - findFieldStructTypeString(field.type, undefined, abi) - ), + ts.factory.createIdentifier(findFieldTypeString(field.type, undefined, abi)), undefined ) }) @@ -178,7 +176,7 @@ export function generateField( findFieldStructType(field.type, namespace, abi), ] - const structTypeString = findFieldStructTypeString(field.type, namespace, abi) + const structTypeString = findFieldTypeString(field.type, namespace, abi) isArray = isArray || structTypeString.endsWith('[]') // Build the options object if needed @@ -304,7 +302,7 @@ function findVariantStructType( namespace: string | undefined, abi: ABI.Def ): ts.Identifier | ts.StringLiteral | ts.ObjectLiteralExpression { - const variantTypeString = findFieldStructTypeString(typeString, namespace, abi) + const variantTypeString = findFieldTypeString(typeString, namespace, abi) if (['string', 'string[]', 'boolean', 'boolean[]'].includes(variantTypeString.toLowerCase())) { return ts.factory.createStringLiteral(formatFieldString(variantTypeString)) @@ -337,9 +335,7 @@ function findFieldStructType( namespace: string | undefined, abi: ABI.Def ): ts.Identifier | ts.StringLiteral { - const fieldTypeString = extractDecorator( - findFieldStructTypeString(typeString, namespace, abi) - ).type + const fieldTypeString = extractDecorator(findFieldTypeString(typeString, namespace, abi)).type if (['string', 'string[]', 'boolean', 'boolean[]'].includes(fieldTypeString.toLowerCase())) { return ts.factory.createStringLiteral(formatFieldString(fieldTypeString)) @@ -348,7 +344,7 @@ function findFieldStructType( return ts.factory.createIdentifier(fieldTypeString) } -function findFieldStructTypeString( +export function findFieldTypeString( typeString: string, namespace: string | undefined, abi: ABI.Def diff --git a/test/data/abis/testing.gm.json b/test/data/abis/testing.gm.json new file mode 100644 index 0000000..2447a6d --- /dev/null +++ b/test/data/abis/testing.gm.json @@ -0,0 +1,539 @@ +{ + "version": "eosio::abi/1.2", + "types": [], + "structs": [ + { + "name": "api_response", + "base": "", + "fields": [ + { + "name": "foo", + "type": "uint64" + } + ] + }, + { + "name": "callapi", + "base": "", + "fields": [] + }, + { + "name": "account_row", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "seeds", + "type": "uint32" + } + ] + }, + { + "name": "addoracle", + "base": "", + "fields": [ + { + "name": "oracle", + "type": "name" + } + ] + }, + { + "name": "advance", + "base": "", + "fields": [] + }, + { + "name": "commit", + "base": "", + "fields": [ + { + "name": "oracle", + "type": "name" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "commit", + "type": "checksum256" + } + ] + }, + { + "name": "commit_row", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "oracle", + "type": "name" + }, + { + "name": "commit", + "type": "checksum256" + } + ] + }, + { + "name": "compute", + "base": "", + "fields": [ + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "seed", + "type": "uint64" + } + ] + }, + { + "name": "destroy", + "base": "", + "fields": [ + { + "name": "owner", + "type": "name" + }, + { + "name": "to_destroy", + "type": "uint64[]" + } + ] + }, + { + "name": "destroy_return_value", + "base": "", + "fields": [ + { + "name": "ram_sold", + "type": "uint64" + }, + { + "name": "redeemed", + "type": "asset" + } + ] + }, + { + "name": "destroyall", + "base": "", + "fields": [] + }, + { + "name": "enable", + "base": "", + "fields": [ + { + "name": "enabled", + "type": "bool" + } + ] + }, + { + "name": "enroll", + "base": "", + "fields": [ + { + "name": "account", + "type": "name" + }, + { + "name": "epoch", + "type": "uint64" + } + ] + }, + { + "name": "epoch_row", + "base": "", + "fields": [ + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "start", + "type": "time_point" + }, + { + "name": "end", + "type": "time_point" + }, + { + "name": "reveal", + "type": "time_point" + }, + { + "name": "complete", + "type": "time_point" + } + ] + }, + { + "name": "generate_return_value", + "base": "", + "fields": [ + { + "name": "seeds", + "type": "uint32" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "cost", + "type": "asset" + }, + { + "name": "refund", + "type": "asset" + }, + { + "name": "total_seeds", + "type": "uint64" + }, + { + "name": "epoch_seeds", + "type": "uint64" + } + ] + }, + { + "name": "generatertrn", + "base": "", + "fields": [] + }, + { + "name": "init", + "base": "", + "fields": [] + }, + { + "name": "oracle_row", + "base": "", + "fields": [ + { + "name": "oracle", + "type": "name" + } + ] + }, + { + "name": "removeoracle", + "base": "", + "fields": [ + { + "name": "oracle", + "type": "name" + } + ] + }, + { + "name": "reveal", + "base": "", + "fields": [ + { + "name": "oracle", + "type": "name" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "reveal", + "type": "string" + } + ] + }, + { + "name": "reveal_row", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "oracle", + "type": "name" + }, + { + "name": "reveal", + "type": "string" + } + ] + }, + { + "name": "seed_row", + "base": "", + "fields": [ + { + "name": "seed", + "type": "uint64" + }, + { + "name": "owner", + "type": "name" + }, + { + "name": "epoch", + "type": "uint64" + } + ] + }, + { + "name": "stat_row", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint64" + }, + { + "name": "account", + "type": "name" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "seeds", + "type": "uint32" + } + ] + }, + { + "name": "state_row", + "base": "", + "fields": [ + { + "name": "id", + "type": "uint16" + }, + { + "name": "epoch", + "type": "uint64" + }, + { + "name": "enabled", + "type": "bool" + } + ] + }, + { + "name": "transfer", + "base": "", + "fields": [ + { + "name": "from", + "type": "name" + }, + { + "name": "to", + "type": "name" + }, + { + "name": "to_transfer", + "type": "uint64[]" + } + ] + }, + { + "name": "wipe", + "base": "", + "fields": [] + }, + { + "name": "wipesome", + "base": "", + "fields": [] + } + ], + "actions": [ + { + "name": "callapi", + "type": "callapi", + "ricardian_contract": "" + }, + { + "name": "addoracle", + "type": "addoracle", + "ricardian_contract": "" + }, + { + "name": "advance", + "type": "advance", + "ricardian_contract": "" + }, + { + "name": "commit", + "type": "commit", + "ricardian_contract": "" + }, + { + "name": "compute", + "type": "compute", + "ricardian_contract": "" + }, + { + "name": "destroy", + "type": "destroy", + "ricardian_contract": "" + }, + { + "name": "destroyall", + "type": "destroyall", + "ricardian_contract": "" + }, + { + "name": "enable", + "type": "enable", + "ricardian_contract": "" + }, + { + "name": "enroll", + "type": "enroll", + "ricardian_contract": "" + }, + { + "name": "generatertrn", + "type": "generatertrn", + "ricardian_contract": "" + }, + { + "name": "init", + "type": "init", + "ricardian_contract": "" + }, + { + "name": "removeoracle", + "type": "removeoracle", + "ricardian_contract": "" + }, + { + "name": "reveal", + "type": "reveal", + "ricardian_contract": "" + }, + { + "name": "transfer", + "type": "transfer", + "ricardian_contract": "" + }, + { + "name": "wipe", + "type": "wipe", + "ricardian_contract": "" + }, + { + "name": "wipesome", + "type": "wipesome", + "ricardian_contract": "" + } + ], + "tables": [ + { + "name": "accounts", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "account_row" + }, + { + "name": "commits", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "commit_row" + }, + { + "name": "epochs", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "epoch_row" + }, + { + "name": "oracles", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "oracle_row" + }, + { + "name": "reveals", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "reveal_row" + }, + { + "name": "seeds", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "seed_row" + }, + { + "name": "state", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "state_row" + }, + { + "name": "stats", + "index_type": "i64", + "key_names": [], + "key_types": [], + "type": "stat_row" + } + ], + "ricardian_clauses": [], + "error_messages": [], + "abi_extensions": [], + "variants": [], + "action_results": [ + { + "name": "callapi", + "result_type": "api_response" + }, + { + "name": "advance", + "result_type": "epoch_row" + }, + { + "name": "compute", + "result_type": "checksum256" + }, + { + "name": "destroy", + "result_type": "destroy_return_value" + }, + { + "name": "generatertrn", + "result_type": "generate_return_value" + } + ] +} diff --git a/test/data/contracts/mock-testing.gm.ts b/test/data/contracts/mock-testing.gm.ts new file mode 100644 index 0000000..3959c67 --- /dev/null +++ b/test/data/contracts/mock-testing.gm.ts @@ -0,0 +1,321 @@ +import type {Action, Checksum256Type, NameType, UInt64Type} from '@wharfkit/antelope' +import { + ABI, + Asset, + Blob, + Checksum256, + Name, + Struct, + TimePoint, + UInt16, + UInt32, + UInt64, +} from '@wharfkit/antelope' +import type {ActionOptions, ContractArgs, PartialBy, Table} from '@wharfkit/contract' +import {Contract as BaseContract} from '@wharfkit/contract' +export const abiBlob = Blob.from( + 'DmVvc2lvOjphYmkvMS4yABsMYXBpX3Jlc3BvbnNlAAEDZm9vBnVpbnQ2NAdjYWxsYXBpAAALYWNjb3VudF9yb3cAAgdhY2NvdW50BG5hbWUFc2VlZHMGdWludDMyCWFkZG9yYWNsZQABBm9yYWNsZQRuYW1lB2FkdmFuY2UAAAZjb21taXQAAwZvcmFjbGUEbmFtZQVlcG9jaAZ1aW50NjQGY29tbWl0C2NoZWNrc3VtMjU2CmNvbW1pdF9yb3cABAJpZAZ1aW50NjQFZXBvY2gGdWludDY0Bm9yYWNsZQRuYW1lBmNvbW1pdAtjaGVja3N1bTI1Ngdjb21wdXRlAAIFZXBvY2gGdWludDY0BHNlZWQGdWludDY0B2Rlc3Ryb3kAAgVvd25lcgRuYW1lCnRvX2Rlc3Ryb3kIdWludDY0W10UZGVzdHJveV9yZXR1cm5fdmFsdWUAAghyYW1fc29sZAZ1aW50NjQIcmVkZWVtZWQFYXNzZXQKZGVzdHJveWFsbAAABmVuYWJsZQABB2VuYWJsZWQEYm9vbAZlbnJvbGwAAgdhY2NvdW50BG5hbWUFZXBvY2gGdWludDY0CWVwb2NoX3JvdwAFBWVwb2NoBnVpbnQ2NAVzdGFydAp0aW1lX3BvaW50A2VuZAp0aW1lX3BvaW50BnJldmVhbAp0aW1lX3BvaW50CGNvbXBsZXRlCnRpbWVfcG9pbnQVZ2VuZXJhdGVfcmV0dXJuX3ZhbHVlAAYFc2VlZHMGdWludDMyBWVwb2NoBnVpbnQ2NARjb3N0BWFzc2V0BnJlZnVuZAVhc3NldAt0b3RhbF9zZWVkcwZ1aW50NjQLZXBvY2hfc2VlZHMGdWludDY0DGdlbmVyYXRlcnRybgAABGluaXQAAApvcmFjbGVfcm93AAEGb3JhY2xlBG5hbWUMcmVtb3Zlb3JhY2xlAAEGb3JhY2xlBG5hbWUGcmV2ZWFsAAMGb3JhY2xlBG5hbWUFZXBvY2gGdWludDY0BnJldmVhbAZzdHJpbmcKcmV2ZWFsX3JvdwAEAmlkBnVpbnQ2NAVlcG9jaAZ1aW50NjQGb3JhY2xlBG5hbWUGcmV2ZWFsBnN0cmluZwhzZWVkX3JvdwADBHNlZWQGdWludDY0BW93bmVyBG5hbWUFZXBvY2gGdWludDY0CHN0YXRfcm93AAQCaWQGdWludDY0B2FjY291bnQEbmFtZQVlcG9jaAZ1aW50NjQFc2VlZHMGdWludDMyCXN0YXRlX3JvdwADAmlkBnVpbnQxNgVlcG9jaAZ1aW50NjQHZW5hYmxlZARib29sCHRyYW5zZmVyAAMEZnJvbQRuYW1lAnRvBG5hbWULdG9fdHJhbnNmZXIIdWludDY0W10Ed2lwZQAACHdpcGVzb21lAAAQAAAAwFUTo0EHY2FsbGFwaQAAAFARmUtTMglhZGRvcmFjbGUAAAAAQKFpdjIHYWR2YW5jZQAAAAAAZCclRQZjb21taXQAAAAAQGVdJUUHY29tcHV0ZQAAAADA05uxSgdkZXN0cm95AABAjMbTm7FKCmRlc3Ryb3lhbGwAAAAAAKh4zFQGZW5hYmxlAAAAAADESO9UBmVucm9sbAAwb74qm6umYgxnZW5lcmF0ZXJ0cm4AAAAAAACQ3XQEaW5pdACgIjKXqk2lugxyZW1vdmVvcmFjbGUAAAAAAESjtroGcmV2ZWFsAAAAAFctPM3NCHRyYW5zZmVyAAAAAAAAoKrjBHdpcGUAAAAASlKsquMId2lwZXNvbWUACAAAADhPTREyA2k2NAAAC2FjY291bnRfcm93AAAAAGcnJUUDaTY0AAAKY29tbWl0X3JvdwAAAADghmhVA2k2NAAACWVwb2NoX3JvdwAAAACriMylA2k2NAAACm9yYWNsZV9yb3cAAAAAR6O2ugNpNjQAAApyZXZlYWxfcm93AAAAAACclMIDaTY0AAAIc2VlZF9yb3cAAAAAAJVNxgNpNjQAAAlzdGF0ZV9yb3cAAAAAAJxNxgNpNjQAAAhzdGF0X3JvdwAAAAAFAAAAwFUTo0EMYXBpX3Jlc3BvbnNlAAAAQKFpdjIJZXBvY2hfcm93AAAAQGVdJUULY2hlY2tzdW0yNTYAAADA05uxShRkZXN0cm95X3JldHVybl92YWx1ZTBvviqbq6ZiFWdlbmVyYXRlX3JldHVybl92YWx1ZQ==' +) +export const abi = ABI.from(abiBlob) +export class Contract extends BaseContract { + constructor(args: PartialBy) { + super({ + client: args.client, + abi: abi, + account: args.account || Name.from('testing.gm'), + }) + } + action( + name: T, + data: ActionNameParams[T], + options?: ActionOptions + ): Action { + return super.action(name, data, options) + } + readonly( + name: T, + data?: ActionNameParams[T] + ): ActionReturnValues[T] { + return super.readonly(name, data) as unknown as ActionReturnValues[T] + } + table(name: T, scope?: NameType): Table> { + return super.table(name, scope, TableMap[name]) + } +} +export interface ActionNameParams { + callapi: ActionParams.callapi + addoracle: ActionParams.addoracle + advance: ActionParams.advance + commit: ActionParams.commit + compute: ActionParams.compute + destroy: ActionParams.destroy + destroyall: ActionParams.destroyall + enable: ActionParams.enable + enroll: ActionParams.enroll + generatertrn: ActionParams.generatertrn + init: ActionParams.init + removeoracle: ActionParams.removeoracle + reveal: ActionParams.reveal + transfer: ActionParams.transfer + wipe: ActionParams.wipe + wipesome: ActionParams.wipesome +} +export namespace ActionParams { + export namespace Type {} + export interface callapi {} + export interface addoracle { + oracle: NameType + } + export interface advance {} + export interface commit { + oracle: NameType + epoch: UInt64Type + commit: Checksum256Type + } + export interface compute { + epoch: UInt64Type + seed: UInt64Type + } + export interface destroy { + owner: NameType + to_destroy: UInt64Type[] + } + export interface destroyall {} + export interface enable { + enabled: boolean + } + export interface enroll { + account: NameType + epoch: UInt64Type + } + export interface generatertrn {} + export interface init {} + export interface removeoracle { + oracle: NameType + } + export interface reveal { + oracle: NameType + epoch: UInt64Type + reveal: string + } + export interface transfer { + from: NameType + to: NameType + to_transfer: UInt64Type[] + } + export interface wipe {} + export interface wipesome {} +} +export namespace Types { + @Struct.type('api_response') + export class api_response extends Struct { + @Struct.field(UInt64) + foo!: UInt64 + } + @Struct.type('callapi') + export class callapi extends Struct {} + @Struct.type('account_row') + export class account_row extends Struct { + @Struct.field(Name) + account!: Name + @Struct.field(UInt32) + seeds!: UInt32 + } + @Struct.type('addoracle') + export class addoracle extends Struct { + @Struct.field(Name) + oracle!: Name + } + @Struct.type('advance') + export class advance extends Struct {} + @Struct.type('commit') + export class commit extends Struct { + @Struct.field(Name) + oracle!: Name + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(Checksum256) + commit!: Checksum256 + } + @Struct.type('commit_row') + export class commit_row extends Struct { + @Struct.field(UInt64) + id!: UInt64 + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(Name) + oracle!: Name + @Struct.field(Checksum256) + commit!: Checksum256 + } + @Struct.type('compute') + export class compute extends Struct { + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(UInt64) + seed!: UInt64 + } + @Struct.type('destroy') + export class destroy extends Struct { + @Struct.field(Name) + owner!: Name + @Struct.field(UInt64, {array: true}) + to_destroy!: UInt64[] + } + @Struct.type('destroy_return_value') + export class destroy_return_value extends Struct { + @Struct.field(UInt64) + ram_sold!: UInt64 + @Struct.field(Asset) + redeemed!: Asset + } + @Struct.type('destroyall') + export class destroyall extends Struct {} + @Struct.type('enable') + export class enable extends Struct { + @Struct.field('bool') + enabled!: boolean + } + @Struct.type('enroll') + export class enroll extends Struct { + @Struct.field(Name) + account!: Name + @Struct.field(UInt64) + epoch!: UInt64 + } + @Struct.type('epoch_row') + export class epoch_row extends Struct { + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(TimePoint) + start!: TimePoint + @Struct.field(TimePoint) + end!: TimePoint + @Struct.field(TimePoint) + reveal!: TimePoint + @Struct.field(TimePoint) + complete!: TimePoint + } + @Struct.type('generate_return_value') + export class generate_return_value extends Struct { + @Struct.field(UInt32) + seeds!: UInt32 + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(Asset) + cost!: Asset + @Struct.field(Asset) + refund!: Asset + @Struct.field(UInt64) + total_seeds!: UInt64 + @Struct.field(UInt64) + epoch_seeds!: UInt64 + } + @Struct.type('generatertrn') + export class generatertrn extends Struct {} + @Struct.type('init') + export class init extends Struct {} + @Struct.type('oracle_row') + export class oracle_row extends Struct { + @Struct.field(Name) + oracle!: Name + } + @Struct.type('removeoracle') + export class removeoracle extends Struct { + @Struct.field(Name) + oracle!: Name + } + @Struct.type('reveal') + export class reveal extends Struct { + @Struct.field(Name) + oracle!: Name + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field('string') + reveal!: string + } + @Struct.type('reveal_row') + export class reveal_row extends Struct { + @Struct.field(UInt64) + id!: UInt64 + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(Name) + oracle!: Name + @Struct.field('string') + reveal!: string + } + @Struct.type('seed_row') + export class seed_row extends Struct { + @Struct.field(UInt64) + seed!: UInt64 + @Struct.field(Name) + owner!: Name + @Struct.field(UInt64) + epoch!: UInt64 + } + @Struct.type('stat_row') + export class stat_row extends Struct { + @Struct.field(UInt64) + id!: UInt64 + @Struct.field(Name) + account!: Name + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field(UInt32) + seeds!: UInt32 + } + @Struct.type('state_row') + export class state_row extends Struct { + @Struct.field(UInt16) + id!: UInt16 + @Struct.field(UInt64) + epoch!: UInt64 + @Struct.field('bool') + enabled!: boolean + } + @Struct.type('transfer') + export class transfer extends Struct { + @Struct.field(Name) + from!: Name + @Struct.field(Name) + to!: Name + @Struct.field(UInt64, {array: true}) + to_transfer!: UInt64[] + } + @Struct.type('wipe') + export class wipe extends Struct {} + @Struct.type('wipesome') + export class wipesome extends Struct {} +} +export const TableMap = { + accounts: Types.account_row, + commits: Types.commit_row, + epochs: Types.epoch_row, + oracles: Types.oracle_row, + reveals: Types.reveal_row, + seeds: Types.seed_row, + state: Types.state_row, + stats: Types.stat_row, +} +export interface TableTypes { + accounts: Types.account_row + commits: Types.commit_row + epochs: Types.epoch_row + oracles: Types.oracle_row + reveals: Types.reveal_row + seeds: Types.seed_row + state: Types.state_row + stats: Types.stat_row +} +export type RowType = T extends keyof TableTypes ? TableTypes[T] : any +export type ActionNames = keyof ActionNameParams +export type TableNames = keyof TableTypes +export interface ActionReturnValues { + callapi: Types.api_response + advance: Types.epoch_row + compute: Checksum256 + destroy: Types.destroy_return_value + generatertrn: Types.generate_return_value +} +export type ActionReturnNames = keyof ActionReturnValues diff --git a/test/data/requests/05ffbae776e329473d0b26058142fbde12780727.json b/test/data/requests/05ffbae776e329473d0b26058142fbde12780727.json new file mode 100644 index 0000000..ea8b39c --- /dev/null +++ b/test/data/requests/05ffbae776e329473d0b26058142fbde12780727.json @@ -0,0 +1,69 @@ +{ + "request": { + "path": "https://jungle4.greymass.com/v1/chain/send_read_only_transaction", + "params": { + "method": "POST", + "body": "{\"transaction\":{\"signatures\":[],\"compression\":1,\"packed_context_free_data\":\"789c63000000010001\",\"packed_trx\":\"789c636040068c0c0d290dbed3379e02b20f840a2f7604d200440c05d1\"}}" + } + }, + "status": 200, + "json": { + "transaction_id": "1fbb7d301410f8d071216f949d216555ad09bb06c719dbec6a7cdcbf366eb642", + "processed": { + "id": "1fbb7d301410f8d071216f949d216555ad09bb06c719dbec6a7cdcbf366eb642", + "block_num": 119350325, + "block_time": "2024-01-16T20:13:06.500", + "producer_block_id": null, + "receipt": { + "status": "executed", + "cpu_usage_us": 0, + "net_usage_words": 8 + }, + "elapsed": 38, + "net_usage": 64, + "scheduled": false, + "action_traces": [ + { + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0, + "receipt": { + "receiver": "testing.gm", + "act_digest": "0bcba5b6899391bd989fe4d3054dd802da3227a6e4377fc2d529ad6df348932d", + "global_sequence": 0, + "recv_sequence": 0, + "auth_sequence": [], + "code_sequence": 265, + "abi_sequence": 96 + }, + "receiver": "testing.gm", + "act": { + "account": "testing.gm", + "name": "callapi", + "authorization": [], + "data": "", + "hex_data": "" + }, + "context_free": false, + "elapsed": 27, + "console": "", + "trx_id": "1fbb7d301410f8d071216f949d216555ad09bb06c719dbec6a7cdcbf366eb642", + "block_num": 119350325, + "block_time": "2024-01-16T20:13:06.500", + "producer_block_id": null, + "account_ram_deltas": [], + "except": null, + "error_code": null, + "return_value_hex_data": "0100000000000000", + "return_value_data": { + "foo": 1 + } + } + ], + "account_ram_delta": null, + "except": null, + "error_code": null + } + }, + "text": "{\"transaction_id\":\"1fbb7d301410f8d071216f949d216555ad09bb06c719dbec6a7cdcbf366eb642\",\"processed\":{\"id\":\"1fbb7d301410f8d071216f949d216555ad09bb06c719dbec6a7cdcbf366eb642\",\"block_num\":119350325,\"block_time\":\"2024-01-16T20:13:06.500\",\"producer_block_id\":null,\"receipt\":{\"status\":\"executed\",\"cpu_usage_us\":0,\"net_usage_words\":8},\"elapsed\":38,\"net_usage\":64,\"scheduled\":false,\"action_traces\":[{\"action_ordinal\":1,\"creator_action_ordinal\":0,\"closest_unnotified_ancestor_action_ordinal\":0,\"receipt\":{\"receiver\":\"testing.gm\",\"act_digest\":\"0bcba5b6899391bd989fe4d3054dd802da3227a6e4377fc2d529ad6df348932d\",\"global_sequence\":0,\"recv_sequence\":0,\"auth_sequence\":[],\"code_sequence\":265,\"abi_sequence\":96},\"receiver\":\"testing.gm\",\"act\":{\"account\":\"testing.gm\",\"name\":\"callapi\",\"authorization\":[],\"data\":\"\",\"hex_data\":\"\"},\"context_free\":false,\"elapsed\":27,\"console\":\"\",\"trx_id\":\"1fbb7d301410f8d071216f949d216555ad09bb06c719dbec6a7cdcbf366eb642\",\"block_num\":119350325,\"block_time\":\"2024-01-16T20:13:06.500\",\"producer_block_id\":null,\"account_ram_deltas\":[],\"except\":null,\"error_code\":null,\"return_value_hex_data\":\"0100000000000000\",\"return_value_data\":{\"foo\":1}}],\"account_ram_delta\":null,\"except\":null,\"error_code\":null}}" +} \ No newline at end of file diff --git a/test/tests/contract-codegen.ts b/test/tests/contract-codegen.ts index 78aede1..8febee8 100644 --- a/test/tests/contract-codegen.ts +++ b/test/tests/contract-codegen.ts @@ -13,6 +13,7 @@ import * as RewardsGm from '$test/data/contracts/mock-rewards.gm' import * as AtomicAssets from '$test/data/contracts/mock-atomicassets' import * as Hegemon from '$test/data/contracts/mock-hegemon.hgm' import * as Boid from '$test/data/contracts/mock-boid' +import * as GreymassTesting from '$test/data/contracts/mock-testing.gm' import {generateCodegenContract, removeCodegenContracts} from '$test/utils/codegen' import {runGenericContractTests} from './helpers/generic' @@ -55,6 +56,10 @@ suite('codegen', async function () { mock: Boid, generated: null, }, + 'testing.gm': { + mock: GreymassTesting, + generated: null, + }, } // Source code diff --git a/test/tests/contract-functionality.ts b/test/tests/contract-functionality.ts index 4f31c4d..99fd7c8 100644 --- a/test/tests/contract-functionality.ts +++ b/test/tests/contract-functionality.ts @@ -1,8 +1,18 @@ -import {Action, Asset, Bytes, Name, PermissionLevel, Serializer, Struct} from '@wharfkit/antelope' +import { + Action, + Asset, + Bytes, + Name, + PermissionLevel, + Serializer, + Struct, + UInt64, +} from '@wharfkit/antelope' import {makeClient} from '@wharfkit/mock-data' import {assert} from 'chai' import * as RewardsGm from '$test/data/contracts/mock-rewards.gm' +import {Contract as ReturnValueContract} from '$test/data/contracts/mock-testing.gm' import {PlaceholderName, PlaceholderPermission} from '@wharfkit/signing-request' import {Table, TableRowCursor} from '@wharfkit/contract' @@ -77,5 +87,13 @@ suite('functionality', function () { assert.instanceOf(user, RewardsGm.Types.user_row) }) }) + suite('return values', function () { + test('helper exists', async function () { + const client = makeClient('https://jungle4.greymass.com') + const contract = new ReturnValueContract({client}) + const result = await contract.readonly('callapi', {}) + assert.instanceOf(result.foo, UInt64) + }) + }) }) }) diff --git a/test/tests/helpers/generic.ts b/test/tests/helpers/generic.ts index 88b4c6e..9d0d6d6 100644 --- a/test/tests/helpers/generic.ts +++ b/test/tests/helpers/generic.ts @@ -56,6 +56,13 @@ export function getMockParams(contract: Contract): ActionDataType { keys: ['PUB_K1_6RrvujLQN1x5Tacbep1KAk8zzKpSThAQXBCKYFfGUYeACcSRFs'], } } + case 'testing.gm': { + return { + oracle: 'foo', + epoch: 1, + commit: 'bar', + } + } default: { throw new Error(`getMockParams not implemented for ${contract.account}`) } diff --git a/yarn.lock b/yarn.lock index 71e585a..6755197 100644 --- a/yarn.lock +++ b/yarn.lock @@ -647,7 +647,7 @@ pako "^2.0.4" tslib "^2.1.0" -"@wharfkit/antelope@^0.7.3", "@wharfkit/antelope@^1.0.0": +"@wharfkit/antelope@^0.7.3", "@wharfkit/antelope@^1.0.0", "@wharfkit/antelope@^1.0.4": version "1.0.0" resolved "https://registry.yarnpkg.com/@wharfkit/antelope/-/antelope-1.0.0.tgz#c3057b70575991be5de3aea19e0c474614783c80" integrity sha512-gwc6L3AzceN/menx9HCV22Ekd3it1wRruY6dIkyfCaV2UBGmfvIVJ3wPaDi4Ppj2k50b86ShSSHdd52jOFd+dg== @@ -673,13 +673,13 @@ dependencies: tslib "^2.1.0" -"@wharfkit/contract@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@wharfkit/contract/-/contract-1.1.1.tgz#2e96476fac45d06684f90b2a54b3cac39e71c760" - integrity sha512-WN6tzVuuacpzD8yo4uZZPdniXk9Q+ZGkBtUQ+mbeOQaEzrsnncOrHJlck20nmSb/EC8ij1EG0xlhnyhKjnvSYQ== +"@wharfkit/contract@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@wharfkit/contract/-/contract-1.1.4.tgz#5d65a7effa02bb71c98a7493cfdca2472578e6d5" + integrity sha512-7jRgyAHrxg0/RJzOoGn4r1Md2Kho2Bozxzv+sn3c5e7ii8w9nQjyyVnYmFEVRFh6pQ0BtR/pqh6wrYJYTfXQIA== dependencies: "@wharfkit/abicache" "^1.2.0" - "@wharfkit/antelope" "^1.0.0" + "@wharfkit/antelope" "^1.0.4" "@wharfkit/signing-request" "^3.1.0" tslib "^2.1.0"