@graphprotocol/graph-cli
Version:
CLI for building for and deploying to The Graph
327 lines (326 loc) • 14.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const immutable_1 = __importDefault(require("immutable"));
const vitest_1 = require("vitest");
const ts = __importStar(require("../../../codegen/typescript"));
const abi_1 = __importDefault(require("../abi"));
const abi_2 = __importDefault(require("./abi"));
let tempdir;
let abi;
let generatedTypes;
vitest_1.describe.concurrent('ABI code generation', () => {
(0, vitest_1.beforeAll)(async () => {
tempdir = await fs_extra_1.default.mkdtemp('abi-codegen');
try {
const filename = path_1.default.join(tempdir, 'ABI.json');
await fs_extra_1.default.writeFile(filename, JSON.stringify([
{
constant: true,
inputs: [],
name: 'read',
outputs: [{ name: '', type: 'bytes32' }],
payable: false,
type: 'function',
},
{
constant: true,
inputs: [
{
name: 'proposalId',
type: 'uint256',
},
{
components: [
{
name: 'foo',
type: 'uint8',
},
{
name: 'bar',
type: 'tuple',
components: [{ name: 'baz', type: 'address' }],
},
],
name: '',
type: 'tuple',
},
],
name: 'getProposal',
outputs: [
{
components: [
{
name: 'result',
type: 'uint8',
},
{
name: 'target',
type: 'address',
},
{
name: 'data',
type: 'bytes',
},
{
name: 'proposer',
type: 'address',
},
{
name: 'feeRecipient',
type: 'address',
},
{
name: 'fee',
type: 'uint256',
},
{
name: 'startTime',
type: 'uint256',
},
{
name: 'yesCount',
type: 'uint256',
},
{
name: 'noCount',
type: 'uint256',
},
],
name: '',
type: 'tuple',
},
],
payable: false,
stateMutability: 'view',
type: 'function',
},
{
type: 'function',
stateMutability: 'view',
payable: 'false',
name: 'getProposals',
outputs: [
{
type: 'uint256',
name: 'size',
},
{
type: 'tuple[]',
components: [
{ name: 'first', type: 'uint256' },
{ name: 'second', type: 'string' },
],
},
],
},
{
type: 'function',
stateMutability: 'view',
name: 'overloaded',
inputs: [
{
type: 'string',
},
],
outputs: [
{
type: 'string',
},
],
},
{
type: 'function',
stateMutability: 'view',
name: 'overloaded',
inputs: [
{
type: 'uint256',
},
],
outputs: [
{
type: 'string',
},
],
},
{
type: 'function',
stateMutability: 'view',
name: 'overloaded',
inputs: [
{
type: 'bytes32',
},
],
outputs: [
{
type: 'string',
},
],
},
]), 'utf-8');
abi = abi_1.default.load('Contract', filename);
const codegen = new abi_2.default(abi);
generatedTypes = codegen.generateTypes();
}
finally {
await fs_extra_1.default.remove(tempdir);
}
});
(0, vitest_1.afterAll)(async () => {
await fs_extra_1.default.remove(tempdir);
});
(0, vitest_1.describe)('Generated types', () => {
(0, vitest_1.test)('All expected types are generated', () => {
(0, vitest_1.expect)(generatedTypes.map(type => type.name)).toEqual([
'Contract__getProposalResultValue0Struct',
'Contract__getProposalInputParam1Struct',
'Contract__getProposalInputParam1BarStruct',
'Contract__getProposalsResultValue1Struct',
'Contract__getProposalsResult',
'Contract',
]);
});
});
(0, vitest_1.describe)('Contract class', () => {
(0, vitest_1.test)('Exists', () => {
(0, vitest_1.expect)(generatedTypes.find(type => type.name === 'Contract')).toBeDefined();
});
(0, vitest_1.test)('Has methods', () => {
const contract = generatedTypes.find(type => type.name === 'Contract');
(0, vitest_1.expect)(contract.methods).toBeInstanceOf(Array);
});
(0, vitest_1.test)('Has `bind` method', () => {
const contract = generatedTypes.find(type => type.name === 'Contract');
(0, vitest_1.expect)(contract.methods.find((method) => method.name === 'bind')).toBeDefined();
});
(0, vitest_1.test)('Has methods for all callable functions', () => {
const contract = generatedTypes.find(type => type.name === 'Contract');
(0, vitest_1.expect)(contract.methods.map((method) => method.name)).toContain('getProposal');
});
});
(0, vitest_1.describe)('Methods for callable functions', () => {
(0, vitest_1.test)('Have correct parameters', () => {
const contract = generatedTypes.find(type => type.name === 'Contract');
(0, vitest_1.expect)(contract.methods.map((method) => [method.name, method.params])).toEqual([
['bind', immutable_1.default.List([ts.param('address', 'Address')])],
['read', immutable_1.default.List()],
['try_read', immutable_1.default.List()],
[
'getProposal',
immutable_1.default.List([
ts.param('proposalId', 'BigInt'),
ts.param('param1', 'Contract__getProposalInputParam1Struct'),
]),
],
[
'try_getProposal',
immutable_1.default.List([
ts.param('proposalId', 'BigInt'),
ts.param('param1', 'Contract__getProposalInputParam1Struct'),
]),
],
['getProposals', immutable_1.default.List()],
['try_getProposals', immutable_1.default.List()],
['overloaded', immutable_1.default.List([ts.param('param0', 'string')])],
['try_overloaded', immutable_1.default.List([ts.param('param0', 'string')])],
['overloaded1', immutable_1.default.List([ts.param('param0', 'BigInt')])],
['try_overloaded1', immutable_1.default.List([ts.param('param0', 'BigInt')])],
['overloaded2', immutable_1.default.List([ts.param('param0', 'Bytes')])],
['try_overloaded2', immutable_1.default.List([ts.param('param0', 'Bytes')])],
]);
});
(0, vitest_1.test)('Have correct return types', () => {
const contract = generatedTypes.find(type => type.name === 'Contract');
(0, vitest_1.expect)(contract.methods.map((method) => [method.name, method.returnType])).toEqual([
['bind', ts.namedType('Contract')],
['read', ts.namedType('Bytes')],
['try_read', 'ethereum.CallResult<Bytes>'],
['getProposal', ts.namedType('Contract__getProposalResultValue0Struct')],
['try_getProposal', 'ethereum.CallResult<Contract__getProposalResultValue0Struct>'],
['getProposals', ts.namedType('Contract__getProposalsResult')],
['try_getProposals', 'ethereum.CallResult<Contract__getProposalsResult>'],
['overloaded', ts.namedType('string')],
['try_overloaded', 'ethereum.CallResult<string>'],
['overloaded1', ts.namedType('string')],
['try_overloaded1', 'ethereum.CallResult<string>'],
['overloaded2', ts.namedType('string')],
['try_overloaded2', 'ethereum.CallResult<string>'],
]);
});
});
(0, vitest_1.describe)('Tuples', () => {
(0, vitest_1.test)('Tuple types exist for function parameters', () => {
let tupleType = generatedTypes.find(type => type.name === 'Contract__getProposalInputParam1Struct');
// Verify that the tuple type has methods
(0, vitest_1.expect)(tupleType.methods).toBeDefined();
// Verify that the tuple type has getters for all tuple fields with
// the right return types
(0, vitest_1.expect)(tupleType.methods.map((method) => [method.name, method.returnType])).toEqual([
['get foo', 'i32'],
['get bar', 'Contract__getProposalInputParam1BarStruct'],
]);
// Inner tuple:
tupleType = generatedTypes.find(type => type.name === 'Contract__getProposalInputParam1BarStruct');
// Verify that the tuple type has methods
(0, vitest_1.expect)(tupleType.methods).toBeDefined();
// Verify that the tuple type has getters for all tuple fields with
// the right return types
(0, vitest_1.expect)(tupleType.methods.map((method) => [method.name, method.returnType])).toEqual([
['get baz', 'Address'],
]);
});
(0, vitest_1.test)('Tuple types exist for function return values', () => {
const tupleType = generatedTypes.find(type => type.name === 'Contract__getProposalResultValue0Struct');
// Verify that the tuple type has methods
(0, vitest_1.expect)(tupleType.methods).toBeDefined();
// Verify that the tuple type has getters for all tuple fields with
// the right return types
(0, vitest_1.expect)(tupleType.methods.map((method) => [method.name, method.returnType])).toEqual([
['get result', 'i32'],
['get target', 'Address'],
['get data', 'Bytes'],
['get proposer', 'Address'],
['get feeRecipient', 'Address'],
['get fee', 'BigInt'],
['get startTime', 'BigInt'],
['get yesCount', 'BigInt'],
['get noCount', 'BigInt'],
]);
});
(0, vitest_1.test)('Function bodies are generated correctly for tuple arrays', () => {
const contract = generatedTypes.find(type => type.name === 'Contract');
const getter = contract.methods.find((method) => method.name === 'getProposals');
(0, vitest_1.expect)(getter.body).not.toContain('toTupleArray<undefined>');
(0, vitest_1.expect)(getter.body).toContain('result[1].toTupleArray<Contract__getProposalsResultValue1Struct>()');
});
});
});