Implement eth_call for methods returning struct type (#59)

* Handle tuple return type in ethereum host API

* Update graph-cli version to fix eth_call error

* Handle all types in struct based on abi

Co-authored-by: prathamesh0 <prathamesh.musale0@gmail.com>
This commit is contained in:
nikugogoi 2021-11-23 11:23:47 +05:30 committed by nabarun
parent f52467f724
commit 31b302c9b5
11 changed files with 341 additions and 247 deletions

View File

@ -5,8 +5,10 @@
import path from 'path'; import path from 'path';
import chai, { assert, expect } from 'chai'; import chai, { assert, expect } from 'chai';
import spies from 'chai-spies'; import spies from 'chai-spies';
import { utils } from 'ethers';
import { getDummyEventData, getTestDatabase } from '../test/utils'; import { getDummyEventData, getTestDatabase } from '../test/utils';
import abi from '../test/subgraph/example1/build/Example1/abis/Example1.json';
import { instantiate } from './loader'; import { instantiate } from './loader';
import { createEvent, createBlock, Block } from './utils'; import { createEvent, createBlock, Block } from './utils';
import { Database } from './database'; import { Database } from './database';
@ -66,18 +68,14 @@ describe('call handler in mapping code', () => {
_start(); _start();
// Create event params data. // Create event params data.
dummyEventData.eventParams = [ const contractInterface = new utils.Interface(abi);
{ const eventFragment = contractInterface.getEvent('Test(string,uint8)');
name: 'param1', dummyEventData.inputs = eventFragment.inputs;
value: 'abc',
kind: 'string' dummyEventData.event = {
}, param1: 'abc',
{ param2: BigInt(123)
name: 'param2', };
value: BigInt(123),
kind: 'uint256'
}
];
// Dummy contract address string. // Dummy contract address string.
const contractAddress = '0xCA6D29232D1435D8198E3E5302495417dD073d61'; const contractAddress = '0xCA6D29232D1435D8198E3E5302495417dD073d61';

View File

@ -3,7 +3,7 @@
// //
import assert from 'assert'; import assert from 'assert';
import { ethers } from 'ethers'; import { ethers, utils } from 'ethers';
import path from 'path'; import path from 'path';
import chai from 'chai'; import chai from 'chai';
import spies from 'chai-spies'; import spies from 'chai-spies';
@ -65,6 +65,8 @@ describe('eden wasm loader tests', async () => {
} }
}; };
const contractInterface = new utils.Interface(edenNetworkAbi);
it('should load the subgraph network wasm', async () => { it('should load the subgraph network wasm', async () => {
const filePath = path.resolve(__dirname, '../test/subgraph/eden/EdenNetwork/EdenNetwork.wasm'); const filePath = path.resolve(__dirname, '../test/subgraph/eden/EdenNetwork/EdenNetwork.wasm');
({ exports } = await instantiate(db, { event: { block: dummyEventData.block } }, filePath, data)); ({ exports } = await instantiate(db, { event: { block: dummyEventData.block } }, filePath, data));
@ -78,43 +80,17 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy SlotClaimedEvent params. // Create dummy SlotClaimedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('SlotClaimed(indexed uint8,indexed address,indexed address,uint128,uint128,uint16,uint16)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'slot', dummyEventData.event = {
kind: 'uint8', slot: 0,
value: 0 owner: ZERO_ADDRESS,
}, delegate: ZERO_ADDRESS,
{ newBidAmount: BigInt(1),
name: 'owner', oldBidAmount: BigInt(1),
kind: 'address', taxNumerator: 1,
value: ZERO_ADDRESS taxDenominator: 1
}, };
{
name: 'delegate',
kind: 'address',
value: ZERO_ADDRESS
},
{
name: 'newBidAmount',
kind: 'uint128',
value: BigInt(1)
},
{
name: 'oldBidAmount',
kind: 'uint128',
value: BigInt(1)
},
{
name: 'taxNumerator',
kind: 'uint16',
value: 1
},
{
name: 'taxDenominator',
kind: 'uint16',
value: 1
}
];
// Create an ethereum event SlotClaimedEvent to be passed to handler. // Create an ethereum event SlotClaimedEvent to be passed to handler.
const slotClaimedEvent = await createEvent(exports, contractAddress, dummyEventData); const slotClaimedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -128,28 +104,14 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy SlotDelegateUpdatedEvent params. // Create dummy SlotDelegateUpdatedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('SlotDelegateUpdated(indexed uint8,indexed address,indexed address,address)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'slot', dummyEventData.event = {
kind: 'uint8', slot: 0,
value: 0 owner: ZERO_ADDRESS,
}, newDelegate: ZERO_ADDRESS,
{ oldDelegate: ZERO_ADDRESS
name: 'owner', };
kind: 'address',
value: ZERO_ADDRESS
},
{
name: 'newDelegate',
kind: 'address',
value: ZERO_ADDRESS
},
{
name: 'oldDelegate',
kind: 'address',
value: ZERO_ADDRESS
}
];
// Create an ethereum event SlotDelegateUpdatedEvent to be passed to handler. // Create an ethereum event SlotDelegateUpdatedEvent to be passed to handler.
const slotClaimedEvent = await createEvent(exports, contractAddress, dummyEventData); const slotClaimedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -163,18 +125,12 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy StakeEvent params. // Create dummy StakeEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('Stake(indexed address,uint256)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'staker', dummyEventData.event = {
kind: 'address', staker: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc',
value: '0xDC7d7A8920C8Eecc098da5B7522a5F31509b5Bfc' stakeAmount: BigInt(1)
}, };
{
name: 'stakeAmount',
kind: 'uint256',
value: BigInt(1)
}
];
// Create an ethereum event StakeEvent to be passed to handler. // Create an ethereum event StakeEvent to be passed to handler.
const stakeEvent = await createEvent(exports, contractAddress, dummyEventData); const stakeEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -188,18 +144,12 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy UnstakeEvent params. // Create dummy UnstakeEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('Unstake(indexed address,uint256)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'staker', dummyEventData.event = {
kind: 'address', staker: ZERO_ADDRESS,
value: ZERO_ADDRESS unstakedAmount: BigInt(1)
}, };
{
name: 'unstakedAmount',
kind: 'uin256',
value: BigInt(1)
}
];
// Create an ethereum event UnstakeEvent to be passed to handler. // Create an ethereum event UnstakeEvent to be passed to handler.
const unstakeEvent = await createEvent(exports, contractAddress, dummyEventData); const unstakeEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -224,6 +174,8 @@ describe('eden wasm loader tests', async () => {
} }
}; };
const contractInterface = new utils.Interface(merkleDistributorAbi);
it('should load the subgraph network distribution wasm', async () => { it('should load the subgraph network distribution wasm', async () => {
const filePath = path.resolve(__dirname, '../test/subgraph/eden/EdenNetworkDistribution/EdenNetworkDistribution.wasm'); const filePath = path.resolve(__dirname, '../test/subgraph/eden/EdenNetworkDistribution/EdenNetworkDistribution.wasm');
({ exports } = await instantiate(db, { event: { block: dummyEventData.block } }, filePath, data)); ({ exports } = await instantiate(db, { event: { block: dummyEventData.block } }, filePath, data));
@ -237,28 +189,14 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy ClaimedEvent params. // Create dummy ClaimedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('Claimed(uint256,uint256,indexed address,uint256)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'index', dummyEventData.event = {
kind: 'uint256', index: BigInt(1),
value: BigInt(1) totalEarned: BigInt(1),
}, account: ZERO_ADDRESS,
{ claimed: BigInt(1)
name: 'totalEarned', };
kind: 'uint256',
value: BigInt(1)
},
{
name: 'account',
kind: 'address',
value: ZERO_ADDRESS
},
{
name: 'claimed',
kind: 'uint256',
value: BigInt(1)
}
];
// Create an ethereum event ClaimedEvent to be passed to handler. // Create an ethereum event ClaimedEvent to be passed to handler.
const claimedEvent = await createEvent(exports, contractAddress, dummyEventData); const claimedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -272,18 +210,12 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy SlashedEvent params. // Create dummy SlashedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('Slashed(indexed address,uint256)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'account', dummyEventData.event = {
kind: 'address', account: ZERO_ADDRESS,
value: ZERO_ADDRESS slashed: BigInt(1)
}, };
{
name: 'slashed',
kind: 'uint256',
value: BigInt(1)
}
];
// Create an ethereum event SlashedEvent to be passed to handler. // Create an ethereum event SlashedEvent to be passed to handler.
const slashedEvent = await createEvent(exports, contractAddress, dummyEventData); const slashedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -297,23 +229,13 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy MerkleRootUpdatedEvent params. // Create dummy MerkleRootUpdatedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('MerkleRootUpdated(bytes32,uint256,string)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'merkleRoot', dummyEventData.event = {
kind: 'bytes32', merkleRoot: ethers.utils.hexlify(ethers.utils.randomBytes(32)),
value: ethers.utils.hexlify(ethers.utils.randomBytes(32)) distributionNumber: BigInt(1),
}, metadataURI: 'abc'
{ };
name: 'distributionNumber',
kind: 'uint256',
value: BigInt(1)
},
{
name: 'metadataURI',
kind: 'string',
value: 'abc'
}
];
// Create an ethereum event MerkleRootUpdatedEvent to be passed to handler. // Create an ethereum event MerkleRootUpdatedEvent to be passed to handler.
const merkleRootUpdatedEvent = await createEvent(exports, contractAddress, dummyEventData); const merkleRootUpdatedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -327,23 +249,13 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy AccountUpdatedEvent params. // Create dummy AccountUpdatedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('AccountUpdated(indexed address,uint256,uint256)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'account', dummyEventData.event = {
kind: 'address', account: ZERO_ADDRESS,
value: ZERO_ADDRESS totalClaimed: BigInt(1),
}, totalSlashed: BigInt(1)
{ };
name: 'totalClaimed',
kind: 'uint256',
value: BigInt(1)
},
{
name: 'totalSlashed',
kind: 'uint256',
value: BigInt(1)
}
];
// Create an ethereum event AccountUpdatedEvent to be passed to handler. // Create an ethereum event AccountUpdatedEvent to be passed to handler.
const accountUpdatedEvent = await createEvent(exports, contractAddress, dummyEventData); const accountUpdatedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -368,6 +280,8 @@ describe('eden wasm loader tests', async () => {
} }
}; };
const contractInterface = new utils.Interface(distributorGovernanceAbi);
it('should load the subgraph network governance wasm', async () => { it('should load the subgraph network governance wasm', async () => {
const filePath = path.resolve(__dirname, '../test/subgraph/eden/EdenNetworkGovernance/EdenNetworkGovernance.wasm'); const filePath = path.resolve(__dirname, '../test/subgraph/eden/EdenNetworkGovernance/EdenNetworkGovernance.wasm');
({ exports } = await instantiate(db, { event: { block: dummyEventData.block } }, filePath, data)); ({ exports } = await instantiate(db, { event: { block: dummyEventData.block } }, filePath, data));
@ -381,13 +295,9 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy BlockProducerAddedEvent params. // Create dummy BlockProducerAddedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('BlockProducerAdded(indexed address)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'produces', dummyEventData.event = { produces: ZERO_ADDRESS };
kind: 'address',
value: ZERO_ADDRESS
}
];
// Create an ethereum event BlockProducerAddedEvent to be passed to handler. // Create an ethereum event BlockProducerAddedEvent to be passed to handler.
const blockProducerAddedEvent = await createEvent(exports, contractAddress, dummyEventData); const blockProducerAddedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -401,13 +311,9 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy BlockProducerRemovedEvent params. // Create dummy BlockProducerRemovedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('BlockProducerRemoved(indexed address)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'producer', dummyEventData.event = { producer: ZERO_ADDRESS };
kind: 'address',
value: ZERO_ADDRESS
}
];
// Create an ethereum event BlockProducerRemovedEvent to be passed to handler. // Create an ethereum event BlockProducerRemovedEvent to be passed to handler.
const blockProducerRemovedEvent = await createEvent(exports, contractAddress, dummyEventData); const blockProducerRemovedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -421,23 +327,13 @@ describe('eden wasm loader tests', async () => {
} = exports; } = exports;
// Create dummy BlockProducerRewardCollectorChangedEvent params. // Create dummy BlockProducerRewardCollectorChangedEvent params.
dummyEventData.eventParams = [ const eventFragment = contractInterface.getEvent('BlockProducerRewardCollectorChanged(indexed address,indexed address)');
{ dummyEventData.inputs = eventFragment.inputs;
name: 'producer', dummyEventData.event = {
kind: 'address', producer: ZERO_ADDRESS,
value: ZERO_ADDRESS collector: ZERO_ADDRESS,
}, metadataURI: 'abc'
{ };
name: 'collector',
kind: 'address',
value: ZERO_ADDRESS
},
{
name: 'metadataURI',
kind: 'string',
value: 'abc'
}
];
// Create an ethereum event BlockProducerRewardCollectorChangedEvent to be passed to handler. // Create an ethereum event BlockProducerRewardCollectorChangedEvent to be passed to handler.
const blockProducerRewardCollectorChangedEvent = await createEvent(exports, contractAddress, dummyEventData); const blockProducerRewardCollectorChangedEvent = await createEvent(exports, contractAddress, dummyEventData);
@ -450,7 +346,9 @@ describe('eden wasm loader tests', async () => {
rewardScheduleChanged rewardScheduleChanged
} = exports; } = exports;
dummyEventData.eventParams = []; const eventFragment = contractInterface.getEvent('RewardScheduleChanged()');
dummyEventData.inputs = eventFragment.inputs;
dummyEventData.event = {};
// Create an ethereum event RewardScheduleChangedEvent to be passed to handler. // Create an ethereum event RewardScheduleChangedEvent to be passed to handler.
const rewardScheduleChangedEvent = await createEvent(exports, contractAddress, dummyEventData); const rewardScheduleChangedEvent = await createEvent(exports, contractAddress, dummyEventData);

View File

@ -138,18 +138,27 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
// TODO: Check for function overloading. // TODO: Check for function overloading.
let result = await contract[functionName](...functionParams); let result = await contract[functionName](...functionParams);
if (!Array.isArray(result)) { // TODO: Check for function overloading.
// Using function signature does not work.
const { outputs } = contract.interface.getFunction(functionName);
assert(outputs);
// If method returns a single value, ethers returns it directly compared to returning multiple values in an array.
if (outputs.length === 1) {
// Put result in an array to map with the outputs array from abi.
result = [result]; result = [result];
} }
// TODO: Check for function overloading. const resultPtrArrayPromise = outputs.map(
// Using function signature does not work. async (
const outputs = contract.interface.getFunction(functionName).outputs; output: any,
index: number
const resultPtrArrayPromise = result.map(async (value: any, index: number) => { ) => toEthereumValue(
assert(outputs); exports,
return toEthereumValue(exports, value, outputs[index].type); output,
}); result[index]
)
);
const resultPtrArray: any[] = await Promise.all(resultPtrArrayPromise); const resultPtrArray: any[] = await Promise.all(resultPtrArrayPromise);
const arrayEthereumValueId = await getIdOfType(TypeId.ArrayEthereumValue); const arrayEthereumValueId = await getIdOfType(TypeId.ArrayEthereumValue);

View File

@ -1,4 +1,4 @@
import { BigNumber } from 'ethers'; import { BigNumber, utils } from 'ethers';
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import debug from 'debug'; import debug from 'debug';
@ -11,12 +11,6 @@ import { TypeId, EthereumValueKind, ValueKind } from './types';
const log = debug('vulcanize:utils'); const log = debug('vulcanize:utils');
interface EventParam {
name: string;
value: any;
kind: string;
}
interface Transaction { interface Transaction {
hash: string; hash: string;
index: number; index: number;
@ -42,7 +36,8 @@ export interface Block {
export interface EventData { export interface EventData {
block: Block; block: Block;
tx: Transaction; tx: Transaction;
eventParams: EventParam[]; inputs: utils.ParamType[];
event: { [key: string]: any }
eventIndex: number; eventIndex: number;
} }
@ -102,16 +97,41 @@ export const fromEthereumValue = async (instanceExports: any, value: any): Promi
* @param type * @param type
* @returns * @returns
*/ */
export const toEthereumValue = async (instanceExports: any, value: any, type: string): Promise<any> => { export const toEthereumValue = async (instanceExports: any, output: utils.ParamType, value: any): Promise<any> => {
const { const {
__newString, __newString,
__newArray,
ByteArray, ByteArray,
Bytes, Bytes,
Address, Address,
ethereum, ethereum,
BigInt BigInt,
id_of_type: getIdOfType
} = instanceExports; } = instanceExports;
const { type } = output;
// For tuple type.
if (type === 'tuple') {
const arrayEthereumValueId = await getIdOfType(TypeId.ArrayEthereumValue);
// Get values for struct elements.
const ethereumValuePromises = output.components
.map(
async (component: utils.ParamType) => toEthereumValue(
instanceExports,
component,
value[component.name]
)
);
const ethereumValues: any[] = await Promise.all(ethereumValuePromises);
const ethereumValuesArrayPtr = await __newArray(arrayEthereumValueId, ethereumValues);
const ethereumTuple = await ethereum.Tuple.wrap(ethereumValuesArrayPtr);
return ethereum.Value.fromTuple(ethereumTuple);
}
// For boolean type. // For boolean type.
if (type === 'bool') { if (type === 'bool') {
return ethereum.Value.fromBoolean(value ? 1 : 0); return ethereum.Value.fromBoolean(value ? 1 : 0);
@ -163,7 +183,8 @@ export const createEvent = async (instanceExports: any, contractAddress: string,
const { const {
tx, tx,
eventIndex, eventIndex,
eventParams: eventParamsData, inputs,
event,
block: blockData block: blockData
} = eventData; } = eventData;
@ -214,10 +235,10 @@ export const createEvent = async (instanceExports: any, contractAddress: string,
txinputPtr txinputPtr
); );
const eventParamArrayPromise = eventParamsData.map(async data => { const eventParamArrayPromise = inputs.map(async input => {
const { name, value, kind } = data; const { name } = input;
const ethValue = await toEthereumValue(instanceExports, value, kind); const ethValue = await toEthereumValue(instanceExports, input, event[name]);
const namePtr = await __newString(name); const namePtr = await __newString(name);
return ethereum.EventParam.__new( return ethereum.EventParam.__new(

View File

@ -133,17 +133,10 @@ export class GraphWatcher {
const eventFragment = contractInterface.getEvent(eventSignature); const eventFragment = contractInterface.getEvent(eventSignature);
const eventParams = eventFragment.inputs.map((input) => {
return {
name: input.name,
value: event[input.name],
kind: input.type
};
});
const data = { const data = {
eventParams: eventParams,
block: blockData, block: blockData,
inputs: eventFragment.inputs,
event,
tx, tx,
eventIndex eventIndex
}; };

View File

@ -5,6 +5,11 @@ pragma solidity ^0.8.0;
contract Example { contract Example {
uint256 private _test; uint256 private _test;
struct Bid {
uint128 bidAmount1;
uint128 bidAmount2;
}
event Test(string param1, uint8 param2); event Test(string param1, uint8 param2);
function getMethod() public view virtual returns (string memory) function getMethod() public view virtual returns (string memory)
@ -12,8 +17,21 @@ contract Example {
return 'test'; return 'test';
} }
function addMethod(uint128 bidAmount1, uint128 bidAmount2) public pure returns (uint) {
return bidAmount1 + bidAmount2;
}
function structMethod(uint128 bidAmount1, uint128 bidAmount2) public pure returns (Bid memory) {
Bid memory bid;
bid.bidAmount1 = bidAmount2;
bid.bidAmount2 = bidAmount1;
return bid;
}
function emitEvent() public virtual returns (bool) { function emitEvent() public virtual returns (bool) {
emit Test('abc', 123); emit Test('abc', 123);
return true; return true;
} }
} }

View File

@ -18,6 +18,30 @@
"name": "Test", "name": "Test",
"type": "event" "type": "event"
}, },
{
"inputs": [
{
"internalType": "uint128",
"name": "bidAmount1",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "bidAmount2",
"type": "uint128"
}
],
"name": "addMethod",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "pure",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "emitEvent", "name": "emitEvent",
@ -43,5 +67,41 @@
], ],
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "bidAmount1",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "bidAmount2",
"type": "uint128"
}
],
"name": "structMethod",
"outputs": [
{
"components": [
{
"internalType": "uint128",
"name": "bidAmount1",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "bidAmount2",
"type": "uint128"
}
],
"internalType": "struct Example.Bid",
"name": "",
"type": "tuple"
}
],
"stateMutability": "pure",
"type": "function"
} }
] ]

View File

@ -32,11 +32,53 @@ export class Test__Params {
} }
} }
export class Example1__structMethodResultValue0Struct extends ethereum.Tuple {
get bidAmount1(): BigInt {
return this[0].toBigInt();
}
get bidAmount2(): BigInt {
return this[1].toBigInt();
}
}
export class Example1 extends ethereum.SmartContract { export class Example1 extends ethereum.SmartContract {
static bind(address: Address): Example1 { static bind(address: Address): Example1 {
return new Example1("Example1", address); return new Example1("Example1", address);
} }
addMethod(bidAmount1: BigInt, bidAmount2: BigInt): BigInt {
let result = super.call(
"addMethod",
"addMethod(uint128,uint128):(uint256)",
[
ethereum.Value.fromUnsignedBigInt(bidAmount1),
ethereum.Value.fromUnsignedBigInt(bidAmount2)
]
);
return result[0].toBigInt();
}
try_addMethod(
bidAmount1: BigInt,
bidAmount2: BigInt
): ethereum.CallResult<BigInt> {
let result = super.tryCall(
"addMethod",
"addMethod(uint128,uint128):(uint256)",
[
ethereum.Value.fromUnsignedBigInt(bidAmount1),
ethereum.Value.fromUnsignedBigInt(bidAmount2)
]
);
if (result.reverted) {
return new ethereum.CallResult();
}
let value = result.value;
return ethereum.CallResult.fromValue(value[0].toBigInt());
}
emitEvent(): boolean { emitEvent(): boolean {
let result = super.call("emitEvent", "emitEvent():(bool)", []); let result = super.call("emitEvent", "emitEvent():(bool)", []);
@ -66,6 +108,45 @@ export class Example1 extends ethereum.SmartContract {
let value = result.value; let value = result.value;
return ethereum.CallResult.fromValue(value[0].toString()); return ethereum.CallResult.fromValue(value[0].toString());
} }
structMethod(
bidAmount1: BigInt,
bidAmount2: BigInt
): Example1__structMethodResultValue0Struct {
let result = super.call(
"structMethod",
"structMethod(uint128,uint128):((uint128,uint128))",
[
ethereum.Value.fromUnsignedBigInt(bidAmount1),
ethereum.Value.fromUnsignedBigInt(bidAmount2)
]
);
return changetype<Example1__structMethodResultValue0Struct>(
result[0].toTuple()
);
}
try_structMethod(
bidAmount1: BigInt,
bidAmount2: BigInt
): ethereum.CallResult<Example1__structMethodResultValue0Struct> {
let result = super.tryCall(
"structMethod",
"structMethod(uint128,uint128):((uint128,uint128))",
[
ethereum.Value.fromUnsignedBigInt(bidAmount1),
ethereum.Value.fromUnsignedBigInt(bidAmount2)
]
);
if (result.reverted) {
return new ethereum.CallResult();
}
let value = result.value;
return ethereum.CallResult.fromValue(
changetype<Example1__structMethodResultValue0Struct>(value[0].toTuple())
);
}
} }
export class EmitEventCall extends ethereum.Call { export class EmitEventCall extends ethereum.Call {

View File

@ -10,7 +10,7 @@
"deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 example1" "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 example1"
}, },
"dependencies": { "dependencies": {
"@graphprotocol/graph-cli": "ssh://git@github.com:vulcanize/graph-cli.git#ng-add-exports", "@graphprotocol/graph-cli": "ssh://git@github.com:vulcanize/graph-cli.git#graph-watcher",
"@graphprotocol/graph-ts": "^0.22.1" "@graphprotocol/graph-ts": "^0.22.1"
} }
} }

View File

@ -62,6 +62,22 @@ export function handleTest (event: Test): void {
// Entities can be written to the store with `.save()` // Entities can be written to the store with `.save()`
entity.save(); entity.save();
const contractAddress = dataSource.address();
const contract = Example1.bind(contractAddress);
// Access functions by calling them.
const res1 = contract.try_addMethod(BigInt.fromString('10'), BigInt.fromString('20'));
if (res1.reverted) {
log.debug('Contract eth call reverted', []);
} else {
log.debug('Contract eth call result: {}', [res1.value.toString()]);
}
// Access functions by calling them.
const res = contract.structMethod(BigInt.fromString('1000'), BigInt.fromString('500'));
log.debug('Contract eth call result: {}', [res.bidAmount1.toString()]);
// Note: If a handler doesn't require existing field values, it is faster // Note: If a handler doesn't require existing field values, it is faster
// _not_ to load the entity from the store. Instead, create it fresh with // _not_ to load the entity from the store. Instead, create it fresh with
// `new Entity(...)`, set the fields that should be updated and save the // `new Entity(...)`, set the fields that should be updated and save the

View File

@ -23,9 +23,9 @@
chalk "^2.0.0" chalk "^2.0.0"
js-tokens "^4.0.0" js-tokens "^4.0.0"
"@graphprotocol/graph-cli@ssh://git@github.com:vulcanize/graph-cli.git#ng-add-exports": "@graphprotocol/graph-cli@ssh://git@github.com:vulcanize/graph-cli.git#graph-watcher":
version "0.22.1" version "0.22.4"
resolved "ssh://git@github.com:vulcanize/graph-cli.git#cae2627e27df7215b8485060fa491fc9854e8dfa" resolved "ssh://git@github.com:vulcanize/graph-cli.git#0f68b8901349493bff3e85072e8cb43fab7b9101"
dependencies: dependencies:
assemblyscript "0.19.10" assemblyscript "0.19.10"
binary-install-raw "0.0.13" binary-install-raw "0.0.13"
@ -75,14 +75,14 @@
"@types/range-parser" "*" "@types/range-parser" "*"
"@types/lodash@^4.14.159": "@types/lodash@^4.14.159":
version "4.14.176" version "4.14.177"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.176.tgz#641150fc1cda36fbfa329de603bbb175d7ee20c0" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578"
integrity sha512-xZmuPTa3rlZoIbtDUyJKZQimJV3bxCmzMIO2c9Pz9afyDro6kr7R79GwcB6mRhuoPmV2p1Vb66WOJH7F886WKQ== integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw==
"@types/node@*": "@types/node@*":
version "16.11.7" version "16.11.9"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.7.tgz#36820945061326978c42a01e56b61cd223dfdc42" resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.9.tgz#879be3ad7af29f4c1a5c433421bf99fab7047185"
integrity sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw== integrity sha512-MKmdASMf3LtPzwLyRrFjtFFZ48cMf8jmX5VRYrDQiJa8Ybu5VAmkqBWqKU8fdCwD8ysw4mQ9nrEHvzg6gunR7A==
"@types/node@^12.12.54": "@types/node@^12.12.54":
version "12.20.37" version "12.20.37"
@ -1371,9 +1371,9 @@ is-circular@^1.0.2:
integrity sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA== integrity sha512-YttjnrswnUYRVJvxCvu8z+PGMUSzC2JttP0OEXezlAEdp3EXzhf7IZ3j0gRAybJBQupedIZFhY61Tga6E0qASA==
is-electron@^2.2.0: is-electron@^2.2.0:
version "2.2.0" version "2.2.1"
resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.0.tgz#8943084f09e8b731b3a7a0298a7b5d56f6b7eef0" resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.1.tgz#751b1dd8a74907422faa5c35aaa0cf66d98086e9"
integrity sha512-SpMppC2XR3YdxSzczXReBjqs2zGscWQpBIKqwXYBFic0ERaxNVgwLCHwOLZeESfdJQjX0RDvrJ1lBXX2ij+G1Q== integrity sha512-r8EEQQsqT+Gn0aXFx7lTFygYQhILLCB+wn0WCDL5LZRINeLH/Rvw1j2oKodELLXYNImQ3CRlVsY8wW4cGOsyuw==
is-extglob@^2.1.1: is-extglob@^2.1.1:
version "2.1.1" version "2.1.1"
@ -1665,9 +1665,9 @@ libp2p-crypto@~0.16.1:
ursa-optional "~0.10.0" ursa-optional "~0.10.0"
lines-and-columns@^1.1.6: lines-and-columns@^1.1.6:
version "1.1.6" version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lodash.camelcase@^4.3.0: lodash.camelcase@^4.3.0:
version "4.3.0" version "4.3.0"
@ -2506,9 +2506,9 @@ side-channel@^1.0.4:
object-inspect "^1.9.0" object-inspect "^1.9.0"
signal-exit@^3.0.2: signal-exit@^3.0.2:
version "3.0.5" version "3.0.6"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af"
integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==
signed-varint@^2.0.1: signed-varint@^2.0.1:
version "2.0.1" version "2.0.1"