mirror of
https://github.com/cerc-io/watcher-ts
synced 2024-11-19 20:36:19 +00:00
Handle subgraph schema entity array type and relation fields (#49)
* Handle relation entities in subgraph * Modify eden-watcher entities to handle subgraph schema data types * Modify schema gql to match eden subgraph gql shape * Handle array type fields in subgraph schema * Fix store get api for array type fields in subgraph entities * Handle array type in eden-watcher and format await used in params
This commit is contained in:
parent
158c3928c9
commit
800ad79baf
@ -48,7 +48,8 @@
|
||||
"multiformats": "^9.4.8",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"typeorm": "^0.2.32",
|
||||
"yargs": "^17.0.1"
|
||||
"yargs": "^17.0.1",
|
||||
"decimal.js": "^10.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ethersproject/abi": "^5.3.0",
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Account } from './Account';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
@ -23,8 +23,8 @@ export class Claim {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
index!: bigint;
|
||||
|
||||
@ManyToOne(() => Account)
|
||||
account!: Account;
|
||||
@Column('varchar')
|
||||
account!: string;
|
||||
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
totalEarned!: bigint;
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Distributor } from './Distributor';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
@ -17,8 +17,8 @@ export class Distribution {
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Distributor)
|
||||
distributor!: Distributor;
|
||||
@Column('varchar')
|
||||
distributor!: string;
|
||||
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
timestamp!: bigint;
|
||||
|
@ -2,8 +2,7 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Distribution } from './Distribution';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class Distributor {
|
||||
@ -16,6 +15,6 @@ export class Distributor {
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Distribution, { nullable: true })
|
||||
currentDistribution!: Distribution;
|
||||
@Column('varchar', { nullable: true })
|
||||
currentDistribution!: string;
|
||||
}
|
||||
|
@ -3,9 +3,10 @@
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Block } from './Block';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
import { ProducerEpoch } from './ProducerEpoch';
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
import { bigintTransformer, decimalTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
export class Epoch {
|
||||
@ -24,11 +25,11 @@ export class Epoch {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
epochNumber!: bigint;
|
||||
|
||||
@ManyToOne(() => Block, { nullable: true })
|
||||
startBlock!: Block;
|
||||
@Column('varchar', { nullable: true })
|
||||
startBlock!: string;
|
||||
|
||||
@ManyToOne(() => Block, { nullable: true })
|
||||
endBlock!: Block;
|
||||
@Column('varchar', { nullable: true })
|
||||
endBlock!: string;
|
||||
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
producerBlocks!: bigint;
|
||||
@ -36,8 +37,8 @@ export class Epoch {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
allBlocks!: bigint;
|
||||
|
||||
@Column('varchar')
|
||||
producerBlocksRatio!: string;
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
producerBlocksRatio!: Decimal;
|
||||
|
||||
@ManyToOne(() => ProducerEpoch)
|
||||
producerRewards!: ProducerEpoch;
|
||||
|
@ -2,10 +2,9 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Slot } from './Slot';
|
||||
import { Staker } from './Staker';
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
import { bigintArrayTransformer, bigintTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
export class Network {
|
||||
@ -18,17 +17,17 @@ export class Network {
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Slot, { nullable: true })
|
||||
slot0!: Slot;
|
||||
@Column('varchar', { nullable: true })
|
||||
slot0!: string;
|
||||
|
||||
@ManyToOne(() => Slot, { nullable: true })
|
||||
slot1!: Slot;
|
||||
@Column('varchar', { nullable: true })
|
||||
slot1!: string;
|
||||
|
||||
@ManyToOne(() => Slot, { nullable: true })
|
||||
slot2!: Slot;
|
||||
@Column('varchar', { nullable: true })
|
||||
slot2!: string;
|
||||
|
||||
@ManyToOne(() => Staker)
|
||||
stakers!: Staker;
|
||||
@Column('varchar', { array: true })
|
||||
stakers!: string[];
|
||||
|
||||
@Column('bigint', { nullable: true, transformer: bigintTransformer })
|
||||
numStakers!: bigint;
|
||||
@ -36,6 +35,6 @@ export class Network {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
totalStaked!: bigint;
|
||||
|
||||
@Column('bigint', { array: true })
|
||||
@Column('bigint', { transformer: bigintArrayTransformer, array: true })
|
||||
stakedPercentiles!: bigint[];
|
||||
}
|
||||
|
@ -2,9 +2,10 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Epoch } from './Epoch';
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
import { bigintTransformer, decimalTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
export class ProducerEpoch {
|
||||
@ -20,8 +21,8 @@ export class ProducerEpoch {
|
||||
@Column('varchar')
|
||||
address!: string;
|
||||
|
||||
@ManyToOne(() => Epoch)
|
||||
epoch!: Epoch;
|
||||
@Column('varchar')
|
||||
epoch!: string;
|
||||
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
totalRewards!: bigint;
|
||||
@ -29,6 +30,6 @@ export class ProducerEpoch {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
blocksProduced!: bigint;
|
||||
|
||||
@Column('varchar')
|
||||
blocksProducedRatio!: string;
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
blocksProducedRatio!: Decimal;
|
||||
}
|
||||
|
@ -2,8 +2,7 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Producer } from './Producer';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class ProducerSet {
|
||||
@ -16,6 +15,6 @@ export class ProducerSet {
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Producer)
|
||||
producers!: Producer;
|
||||
@Column('varchar', { array: true })
|
||||
producers!: string[];
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ export class ProducerSetChange {
|
||||
@Column('varchar')
|
||||
producer!: string;
|
||||
|
||||
@Column('integer')
|
||||
@Column({
|
||||
type: 'enum',
|
||||
enum: ProducerSetChangeType
|
||||
})
|
||||
changeType!: ProducerSetChangeType;
|
||||
}
|
||||
|
@ -2,9 +2,7 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { RewardScheduleEntry } from './RewardScheduleEntry';
|
||||
import { Epoch } from './Epoch';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class RewardSchedule {
|
||||
@ -17,15 +15,15 @@ export class RewardSchedule {
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => RewardScheduleEntry)
|
||||
rewardScheduleEntries!: RewardScheduleEntry;
|
||||
@Column('varchar', { array: true })
|
||||
rewardScheduleEntries!: string[];
|
||||
|
||||
@ManyToOne(() => Epoch, { nullable: true })
|
||||
lastEpoch!: Epoch;
|
||||
@Column('varchar', { nullable: true })
|
||||
lastEpoch!: string;
|
||||
|
||||
@ManyToOne(() => Epoch, { nullable: true })
|
||||
pendingEpoch!: Epoch;
|
||||
@Column('varchar', { nullable: true })
|
||||
pendingEpoch!: string;
|
||||
|
||||
@ManyToOne(() => RewardScheduleEntry, { nullable: true })
|
||||
activeRewardScheduleEntry!: RewardScheduleEntry;
|
||||
@Column('varchar', { nullable: true })
|
||||
activeRewardScheduleEntry!: string;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Account } from './Account';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
@ -20,8 +20,8 @@ export class Slash {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
timestamp!: bigint;
|
||||
|
||||
@ManyToOne(() => Account)
|
||||
account!: Account;
|
||||
@Column('varchar')
|
||||
account!: string;
|
||||
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
slashed!: bigint;
|
||||
|
@ -3,8 +3,11 @@
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
import { bigintTransformer, decimalTransformer } from '@vulcanize/util';
|
||||
|
||||
import { SlotClaim } from './SlotClaim';
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
export class Slot {
|
||||
@ -35,8 +38,8 @@ export class Slot {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
expirationTime!: bigint;
|
||||
|
||||
@Column('varchar')
|
||||
taxRatePerDay!: string;
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
taxRatePerDay!: Decimal;
|
||||
|
||||
@ManyToOne(() => SlotClaim)
|
||||
claims!: SlotClaim;
|
||||
|
@ -2,9 +2,10 @@
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column, ManyToOne } from 'typeorm';
|
||||
import { Slot } from './Slot';
|
||||
import { bigintTransformer } from '@vulcanize/util';
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
import { bigintTransformer, decimalTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
export class SlotClaim {
|
||||
@ -17,8 +18,8 @@ export class SlotClaim {
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@ManyToOne(() => Slot)
|
||||
slot!: Slot;
|
||||
@Column('varchar')
|
||||
slot!: string;
|
||||
|
||||
@Column('varchar')
|
||||
owner!: string;
|
||||
@ -35,6 +36,6 @@ export class SlotClaim {
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
expirationTime!: bigint;
|
||||
|
||||
@Column('varchar')
|
||||
taxRatePerDay!: string;
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
taxRatePerDay!: Decimal;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
scalar BigInt
|
||||
|
||||
scalar Bytes
|
||||
|
||||
scalar BigDecimal
|
||||
|
||||
type Proof {
|
||||
data: String!
|
||||
}
|
||||
@ -239,7 +243,7 @@ type Query {
|
||||
type Producer {
|
||||
id: ID!
|
||||
active: Boolean!
|
||||
rewardCollector: String
|
||||
rewardCollector: Bytes
|
||||
rewards: BigInt!
|
||||
confirmedBlocks: BigInt!
|
||||
pendingEpochBlocks: BigInt!
|
||||
@ -253,7 +257,7 @@ type ProducerSet {
|
||||
type ProducerSetChange {
|
||||
id: ID!
|
||||
blockNumber: BigInt!
|
||||
producer: String!
|
||||
producer: Bytes!
|
||||
changeType: ProducerSetChangeType!
|
||||
}
|
||||
|
||||
@ -265,8 +269,8 @@ enum ProducerSetChangeType {
|
||||
type ProducerRewardCollectorChange {
|
||||
id: ID!
|
||||
blockNumber: BigInt!
|
||||
producer: String!
|
||||
rewardCollector: String!
|
||||
producer: Bytes!
|
||||
rewardCollector: Bytes!
|
||||
}
|
||||
|
||||
type RewardScheduleEntry {
|
||||
@ -311,39 +315,39 @@ type Epoch {
|
||||
endBlock: Block
|
||||
producerBlocks: BigInt!
|
||||
allBlocks: BigInt!
|
||||
producerBlocksRatio: String!
|
||||
producerBlocksRatio: BigDecimal!
|
||||
producerRewards: [ProducerEpoch!]!
|
||||
}
|
||||
|
||||
type ProducerEpoch {
|
||||
id: ID!
|
||||
address: String!
|
||||
address: Bytes!
|
||||
epoch: Epoch!
|
||||
totalRewards: BigInt!
|
||||
blocksProduced: BigInt!
|
||||
blocksProducedRatio: String!
|
||||
blocksProducedRatio: BigDecimal!
|
||||
}
|
||||
|
||||
type SlotClaim {
|
||||
id: ID!
|
||||
slot: Slot!
|
||||
owner: String!
|
||||
owner: Bytes!
|
||||
winningBid: BigInt!
|
||||
oldBid: BigInt!
|
||||
startTime: BigInt!
|
||||
expirationTime: BigInt!
|
||||
taxRatePerDay: String!
|
||||
taxRatePerDay: BigDecimal!
|
||||
}
|
||||
|
||||
type Slot {
|
||||
id: ID!
|
||||
owner: String!
|
||||
delegate: String!
|
||||
owner: Bytes!
|
||||
delegate: Bytes!
|
||||
winningBid: BigInt!
|
||||
oldBid: BigInt!
|
||||
startTime: BigInt!
|
||||
expirationTime: BigInt!
|
||||
taxRatePerDay: String!
|
||||
taxRatePerDay: BigDecimal!
|
||||
claims: [SlotClaim!]!
|
||||
}
|
||||
|
||||
@ -374,7 +378,7 @@ type Distribution {
|
||||
distributor: Distributor!
|
||||
timestamp: BigInt!
|
||||
distributionNumber: BigInt!
|
||||
merkleRoot: String!
|
||||
merkleRoot: Bytes!
|
||||
metadataURI: String!
|
||||
}
|
||||
|
||||
|
@ -90,14 +90,14 @@ export class Database {
|
||||
|
||||
return true;
|
||||
}).map(async (field) => {
|
||||
const { type, propertyName } = field;
|
||||
|
||||
// Fill _blockNumber as blockNumber and _blockHash as blockHash in the entityInstance (wasm).
|
||||
if (['_blockNumber', '_blockHash'].includes(propertyName)) {
|
||||
return toEntityValue(instanceExports, entityInstance, data, type.toString(), propertyName.slice(1));
|
||||
if (['_blockNumber', '_blockHash'].includes(field.propertyName)) {
|
||||
field.propertyName = field.propertyName.slice(1);
|
||||
|
||||
return toEntityValue(instanceExports, entityInstance, data, field);
|
||||
}
|
||||
|
||||
return toEntityValue(instanceExports, entityInstance, data, type.toString(), propertyName);
|
||||
return toEntityValue(instanceExports, entityInstance, data, field);
|
||||
}, {});
|
||||
|
||||
await Promise.all(entityValuePromises);
|
||||
@ -115,7 +115,7 @@ export class Database {
|
||||
|
||||
async getEntityValues (instanceExports: any, block: Block, entityInstance: any, entityFields: any): Promise<{ [key: string]: any } > {
|
||||
const entityValuePromises = entityFields.map(async (field: any) => {
|
||||
const { type, propertyName } = field;
|
||||
const { propertyName } = field;
|
||||
|
||||
// Get blockHash property for db entry from block instance.
|
||||
if (propertyName === 'blockHash') {
|
||||
@ -129,10 +129,10 @@ export class Database {
|
||||
|
||||
// Get blockNumber as _blockNumber and blockHash as _blockHash from the entityInstance (wasm).
|
||||
if (['_blockNumber', '_blockHash'].includes(propertyName)) {
|
||||
return fromEntityValue(instanceExports, entityInstance, type.toString(), propertyName.slice(1));
|
||||
return fromEntityValue(instanceExports, entityInstance, propertyName);
|
||||
}
|
||||
|
||||
return fromEntityValue(instanceExports, entityInstance, type.toString(), propertyName);
|
||||
return fromEntityValue(instanceExports, entityInstance, propertyName);
|
||||
}, {});
|
||||
|
||||
const entityValues = await Promise.all(entityValuePromises);
|
||||
|
@ -105,17 +105,27 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
'ethereum.call': async (call: number) => {
|
||||
const smartContractCall = await ethereum.SmartContractCall.wrap(call);
|
||||
|
||||
const contractAddress = await Address.wrap(await smartContractCall.contractAddress);
|
||||
const contractName = __getString(await smartContractCall.contractName);
|
||||
const functionName = __getString(await smartContractCall.functionName);
|
||||
const functionSignature = __getString(await smartContractCall.functionSignature);
|
||||
let functionParams = __getArray(await smartContractCall.functionParams);
|
||||
const contractAddressPtr = await smartContractCall.contractAddress;
|
||||
const contractAddress = await Address.wrap(contractAddressPtr);
|
||||
|
||||
const contractNamePtr = await smartContractCall.contractName;
|
||||
const contractName = __getString(contractNamePtr);
|
||||
|
||||
const functionNamePtr = await smartContractCall.functionName;
|
||||
const functionName = __getString(functionNamePtr);
|
||||
|
||||
const functionSignaturePtr = await smartContractCall.functionSignature;
|
||||
const functionSignature = __getString(functionSignaturePtr);
|
||||
|
||||
const functionParamsPtr = await smartContractCall.functionParams;
|
||||
let functionParams = __getArray(functionParamsPtr);
|
||||
|
||||
console.log('ethereum.call params');
|
||||
console.log('functionSignature:', functionSignature);
|
||||
|
||||
const abi = abis[contractName];
|
||||
const contract = new Contract(__getString(await contractAddress.toHexString()), abi, provider);
|
||||
const contractAddressStringPtr = await contractAddress.toHexString();
|
||||
const contract = new Contract(__getString(contractAddressStringPtr), abi, provider);
|
||||
|
||||
try {
|
||||
const functionParamsPromise = functionParams.map(async param => {
|
||||
@ -142,7 +152,8 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
});
|
||||
|
||||
const resultPtrArray: any[] = await Promise.all(resultPtrArrayPromise);
|
||||
const res = await __newArray(await getIdOfType(TypeId.ArrayEthereumValue), resultPtrArray);
|
||||
const arrayEthereumValueId = await getIdOfType(TypeId.ArrayEthereumValue);
|
||||
const res = await __newArray(arrayEthereumValueId, resultPtrArray);
|
||||
|
||||
return res;
|
||||
} catch (err) {
|
||||
@ -194,10 +205,12 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
|
||||
const bigDecimaly = BigDecimal.wrap(y);
|
||||
|
||||
const yDigitsBigIntArray = __getArray(await bigDecimaly.digits);
|
||||
const digitsPtr = await bigDecimaly.digits;
|
||||
const yDigitsBigIntArray = __getArray(digitsPtr);
|
||||
const yDigits = BigNumber.from(yDigitsBigIntArray);
|
||||
|
||||
const yExpBigIntArray = __getArray(await bigDecimaly.exp);
|
||||
const expPtr = await bigDecimaly.exp;
|
||||
const yExpBigIntArray = __getArray(expPtr);
|
||||
const yExp = BigNumber.from(yExpBigIntArray);
|
||||
|
||||
console.log('y digits and exp', yDigits, yExp);
|
||||
@ -205,11 +218,17 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
'bigDecimal.toString': async (bigDecimal: number) => {
|
||||
const bigDecimalInstance = BigDecimal.wrap(bigDecimal);
|
||||
|
||||
const digitsBigInt = BigInt.wrap(await bigDecimalInstance.digits);
|
||||
const expBigInt = BigInt.wrap(await bigDecimalInstance.exp);
|
||||
const digitsPtr = await bigDecimalInstance.digits;
|
||||
const digitsBigInt = BigInt.wrap(digitsPtr);
|
||||
|
||||
const digits = __getString(await digitsBigInt.toString());
|
||||
const exp = __getString(await expBigInt.toString());
|
||||
const expPtr = await bigDecimalInstance.exp;
|
||||
const expBigInt = BigInt.wrap(expPtr);
|
||||
|
||||
const digitsStringPtr = await digitsBigInt.toString();
|
||||
const digits = __getString(digitsStringPtr);
|
||||
|
||||
const expStringPtr = await expBigInt.toString();
|
||||
const exp = __getString(expStringPtr);
|
||||
|
||||
const decimal = new Decimal(`${digits}e${exp}`);
|
||||
const ptr = __newString(decimal.toFixed());
|
||||
@ -224,11 +243,13 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
const digits = decimal.d.join('');
|
||||
const digitsBigNumber = BigNumber.from(digits);
|
||||
const signBigNumber = BigNumber.from(decimal.s);
|
||||
const digitsBigInt = await BigInt.fromString(await __newString(digitsBigNumber.mul(signBigNumber).toString()));
|
||||
const digitsStringPtr = await __newString(digitsBigNumber.mul(signBigNumber).toString());
|
||||
const digitsBigInt = await BigInt.fromString(digitsStringPtr);
|
||||
|
||||
// Calculate exp after converting digits to BigInt above.
|
||||
const exp = decimal.e - digits.length + 1;
|
||||
const expBigInt = await BigInt.fromString(await __newString(exp.toString()));
|
||||
const expStringPtr = await __newString(exp.toString());
|
||||
const expBigInt = await BigInt.fromString(expStringPtr);
|
||||
|
||||
const bigDecimal = await BigDecimal.__new(digitsBigInt);
|
||||
bigDecimal.exp = expBigInt;
|
||||
@ -259,10 +280,12 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
},
|
||||
'bigInt.plus': async (x: number, y: number) => {
|
||||
const xBigInt = await BigInt.wrap(x);
|
||||
const xBigNumber = BigNumber.from(__getString(await xBigInt.toString()));
|
||||
const xStringPtr = await xBigInt.toString();
|
||||
const xBigNumber = BigNumber.from(__getString(xStringPtr));
|
||||
|
||||
const yBigInt = await BigInt.wrap(y);
|
||||
const yBigNumber = BigNumber.from(__getString(await yBigInt.toString()));
|
||||
const yStringPtr = await yBigInt.toString();
|
||||
const yBigNumber = BigNumber.from(__getString(yStringPtr));
|
||||
|
||||
const sum = xBigNumber.add(yBigNumber);
|
||||
const ptr = await __newString(sum.toString());
|
||||
@ -272,10 +295,12 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
},
|
||||
'bigInt.minus': async (x: number, y: number) => {
|
||||
const xBigInt = await BigInt.wrap(x);
|
||||
const xBigNumber = BigNumber.from(__getString(await xBigInt.toString()));
|
||||
const xStringPtr = await xBigInt.toString();
|
||||
const xBigNumber = BigNumber.from(__getString(xStringPtr));
|
||||
|
||||
const yBigInt = await BigInt.wrap(y);
|
||||
const yBigNumber = BigNumber.from(__getString(await yBigInt.toString()));
|
||||
const yStringPtr = await yBigInt.toString();
|
||||
const yBigNumber = BigNumber.from(__getString(yStringPtr));
|
||||
|
||||
const diff = xBigNumber.sub(yBigNumber);
|
||||
const ptr = await __newString(diff.toString());
|
||||
@ -285,10 +310,12 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
},
|
||||
'bigInt.times': async (x: number, y: number) => {
|
||||
const xBigInt = await BigInt.wrap(x);
|
||||
const xBigNumber = BigNumber.from(__getString(await xBigInt.toString()));
|
||||
const xStringPtr = await xBigInt.toString();
|
||||
const xBigNumber = BigNumber.from(__getString(xStringPtr));
|
||||
|
||||
const yBigInt = await BigInt.wrap(y);
|
||||
const yBigNumber = BigNumber.from(__getString(await yBigInt.toString()));
|
||||
const yStringPtr = await yBigInt.toString();
|
||||
const yBigNumber = BigNumber.from(__getString(yStringPtr));
|
||||
|
||||
const product = xBigNumber.mul(yBigNumber);
|
||||
const ptr = await __newString(product.toString());
|
||||
@ -298,10 +325,12 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
},
|
||||
'bigInt.dividedBy': async (x: number, y: number) => {
|
||||
const xBigInt = await BigInt.wrap(x);
|
||||
const xBigNumber = BigNumber.from(__getString(await xBigInt.toString()));
|
||||
const xStringPtr = await xBigInt.toString();
|
||||
const xBigNumber = BigNumber.from(__getString(xStringPtr));
|
||||
|
||||
const yBigInt = await BigInt.wrap(y);
|
||||
const yBigNumber = BigNumber.from(__getString(await yBigInt.toString()));
|
||||
const yStringPtr = await yBigInt.toString();
|
||||
const yBigNumber = BigNumber.from(__getString(yStringPtr));
|
||||
|
||||
const quotient = xBigNumber.div(yBigNumber);
|
||||
const ptr = await __newString(quotient.toString());
|
||||
@ -334,7 +363,8 @@ export const instantiate = async (database: Database, indexer: IndexerInterface,
|
||||
datasource: {
|
||||
'dataSource.address': async () => {
|
||||
assert(dataSource);
|
||||
return Address.fromString(await __newString(dataSource.address));
|
||||
const addressStringPtr = await __newString(dataSource.address);
|
||||
return Address.fromString(addressStringPtr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -3,9 +3,11 @@ import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import debug from 'debug';
|
||||
import yaml from 'js-yaml';
|
||||
import Decimal from 'decimal.js';
|
||||
import { ColumnType } from 'typeorm';
|
||||
import { ColumnMetadata } from 'typeorm/metadata/ColumnMetadata';
|
||||
|
||||
import { TypeId, EthereumValueKind, ValueKind } from './types';
|
||||
import Decimal from 'decimal.js';
|
||||
|
||||
const log = debug('vulcanize:utils');
|
||||
|
||||
@ -57,7 +59,8 @@ export const fromEthereumValue = async (instanceExports: any, value: any): Promi
|
||||
|
||||
switch (kind) {
|
||||
case EthereumValueKind.ADDRESS: {
|
||||
const address = Address.wrap(await value.toAddress());
|
||||
const addressPtr = await value.toAddress();
|
||||
const address = Address.wrap(addressPtr);
|
||||
const addressStringPtr = await address.toHexString();
|
||||
return __getString(addressStringPtr);
|
||||
}
|
||||
@ -76,7 +79,8 @@ export const fromEthereumValue = async (instanceExports: any, value: any): Promi
|
||||
|
||||
case EthereumValueKind.INT:
|
||||
case EthereumValueKind.UINT: {
|
||||
const bigInt = BigInt.wrap(await value.toBigInt());
|
||||
const bigIntPtr = await value.toBigInt();
|
||||
const bigInt = BigInt.wrap(bigIntPtr);
|
||||
const bigIntStringPtr = await bigInt.toString();
|
||||
const bigIntString = __getString(bigIntStringPtr);
|
||||
return BigNumber.from(bigIntString);
|
||||
@ -113,8 +117,8 @@ export const toEthereumValue = async (instanceExports: any, value: any, type: st
|
||||
|
||||
// For uint/int type or enum type.
|
||||
if (isIntegerOrEnum) {
|
||||
const valueString = await __newString(value.toString());
|
||||
const bigInt = await BigInt.fromString(valueString);
|
||||
const valueStringPtr = await __newString(value.toString());
|
||||
const bigInt = await BigInt.fromString(valueStringPtr);
|
||||
let ethereumValue = await ethereum.Value.fromUnsignedBigInt(bigInt);
|
||||
|
||||
if (Boolean(isInteger) && !isUnsigned) {
|
||||
@ -125,18 +129,23 @@ export const toEthereumValue = async (instanceExports: any, value: any, type: st
|
||||
}
|
||||
|
||||
if (type.startsWith('address')) {
|
||||
return ethereum.Value.fromAddress(await Address.fromString(await __newString(value)));
|
||||
const valueStringPtr = await __newString(value);
|
||||
const addressPtr = await Address.fromString(valueStringPtr);
|
||||
|
||||
return ethereum.Value.fromAddress(addressPtr);
|
||||
}
|
||||
|
||||
// TODO: Check between fixed bytes and dynamic bytes.
|
||||
if (type.startsWith('bytes')) {
|
||||
const byteArray = await ByteArray.fromHexString(await __newString(value));
|
||||
const valueStringPtr = await __newString(value);
|
||||
const byteArray = await ByteArray.fromHexString(valueStringPtr);
|
||||
const bytes = await Bytes.fromByteArray(byteArray);
|
||||
return ethereum.Value.fromBytes(bytes);
|
||||
}
|
||||
|
||||
// For string type.
|
||||
return ethereum.Value.fromString(await __newString(value));
|
||||
const valueStringPtr = await __newString(value);
|
||||
return ethereum.Value.fromString(valueStringPtr);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -168,14 +177,22 @@ export const createEvent = async (instanceExports: any, contractAddress: string,
|
||||
const block = await createBlock(instanceExports, blockData);
|
||||
|
||||
// Fill transaction data.
|
||||
const txHashByteArray = await ByteArray.fromHexString(await __newString(tx.hash));
|
||||
const txHashStringPtr = await __newString(tx.hash);
|
||||
const txHashByteArray = await ByteArray.fromHexString(txHashStringPtr);
|
||||
const txHash = await Bytes.fromByteArray(txHashByteArray);
|
||||
|
||||
const txIndex = await BigInt.fromI32(tx.index);
|
||||
|
||||
const txFrom = await Address.fromString(await __newString(tx.from));
|
||||
const txFromStringPtr = await __newString(tx.from);
|
||||
const txFrom = await Address.fromString(txFromStringPtr);
|
||||
|
||||
const txTo = tx.to && await Address.fromString(await __newString(tx.to));
|
||||
const txToStringPtr = await __newString(tx.to);
|
||||
const txTo = tx.to && await Address.fromString(txToStringPtr);
|
||||
|
||||
const txValuePtr = await BigInt.fromI32(0);
|
||||
const txGasLimitPtr = await BigInt.fromI32(0);
|
||||
const txGasPricePtr = await BigInt.fromI32(0);
|
||||
const txinputPtr = await Bytes.empty();
|
||||
|
||||
// Missing fields from watcher in transaction data:
|
||||
// value
|
||||
@ -187,33 +204,39 @@ export const createEvent = async (instanceExports: any, contractAddress: string,
|
||||
txIndex,
|
||||
txFrom,
|
||||
txTo,
|
||||
await BigInt.fromI32(0),
|
||||
await BigInt.fromI32(0),
|
||||
await BigInt.fromI32(0),
|
||||
await Bytes.empty()
|
||||
txValuePtr,
|
||||
txGasLimitPtr,
|
||||
txGasPricePtr,
|
||||
txinputPtr
|
||||
);
|
||||
|
||||
const eventParamArrayPromise = eventParamsData.map(async data => {
|
||||
const { name, value, kind } = data;
|
||||
|
||||
const ethValue = await toEthereumValue(instanceExports, value, kind);
|
||||
const namePtr = await __newString(name);
|
||||
|
||||
return ethereum.EventParam.__new(
|
||||
await __newString(name),
|
||||
namePtr,
|
||||
ethValue
|
||||
);
|
||||
});
|
||||
|
||||
const eventParamArray = await Promise.all(eventParamArrayPromise);
|
||||
const eventParams = await __newArray(await idOfType(TypeId.ArrayEventParam), eventParamArray);
|
||||
const arrayEventParamId = await idOfType(TypeId.ArrayEventParam);
|
||||
const eventParams = await __newArray(arrayEventParamId, eventParamArray);
|
||||
|
||||
const addStrPtr = await __newString(contractAddress);
|
||||
const eventAddressPtr = await Address.fromString(addStrPtr);
|
||||
|
||||
const eventIndexPtr = await BigInt.fromI32(eventIndex);
|
||||
const transactionLogIndexPtr = await BigInt.fromI32(0);
|
||||
|
||||
// Create event to be passed to handler.
|
||||
return ethereum.Event.__new(
|
||||
await Address.fromString(addStrPtr),
|
||||
await BigInt.fromI32(eventIndex),
|
||||
await BigInt.fromI32(0),
|
||||
eventAddressPtr,
|
||||
eventIndexPtr,
|
||||
transactionLogIndexPtr,
|
||||
null,
|
||||
block,
|
||||
transaction,
|
||||
@ -232,26 +255,40 @@ export const createBlock = async (instanceExports: any, blockData: Block): Promi
|
||||
} = instanceExports;
|
||||
|
||||
// Fill block data.
|
||||
const blockHashByteArray = await ByteArray.fromHexString(await __newString(blockData.blockHash));
|
||||
const blockHashStringPtr = await __newString(blockData.blockHash);
|
||||
const blockHashByteArray = await ByteArray.fromHexString(blockHashStringPtr);
|
||||
const blockHash = await Bytes.fromByteArray(blockHashByteArray);
|
||||
|
||||
const parentHashByteArray = await ByteArray.fromHexString(await __newString(blockData.parentHash));
|
||||
const parentHashStringPtr = await __newString(blockData.parentHash);
|
||||
const parentHashByteArray = await ByteArray.fromHexString(parentHashStringPtr);
|
||||
const parentHash = await Bytes.fromByteArray(parentHashByteArray);
|
||||
|
||||
const blockNumber = await BigInt.fromString(await __newString(blockData.blockNumber));
|
||||
const blockNumberStringPtr = await __newString(blockData.blockNumber);
|
||||
const blockNumber = await BigInt.fromString(blockNumberStringPtr);
|
||||
|
||||
const blockTimestamp = await BigInt.fromString(await __newString(blockData.timestamp));
|
||||
const timestampStringPtr = await __newString(blockData.timestamp);
|
||||
const blockTimestamp = await BigInt.fromString(timestampStringPtr);
|
||||
|
||||
const stateRootByteArray = await ByteArray.fromHexString(await __newString(blockData.stateRoot));
|
||||
const stateRootStringPtr = await __newString(blockData.stateRoot);
|
||||
const stateRootByteArray = await ByteArray.fromHexString(stateRootStringPtr);
|
||||
const stateRoot = await Bytes.fromByteArray(stateRootByteArray);
|
||||
|
||||
const transactionsRootByteArray = await ByteArray.fromHexString(await __newString(blockData.txRoot));
|
||||
const txRootStringPtr = await __newString(blockData.txRoot);
|
||||
const transactionsRootByteArray = await ByteArray.fromHexString(txRootStringPtr);
|
||||
const transactionsRoot = await Bytes.fromByteArray(transactionsRootByteArray);
|
||||
|
||||
const receiptsRootByteArray = await ByteArray.fromHexString(await __newString(blockData.receiptRoot));
|
||||
const receiptRootStringPtr = await __newString(blockData.receiptRoot);
|
||||
const receiptsRootByteArray = await ByteArray.fromHexString(receiptRootStringPtr);
|
||||
const receiptsRoot = await Bytes.fromByteArray(receiptsRootByteArray);
|
||||
|
||||
const totalDifficulty = await BigInt.fromString(await __newString(blockData.td));
|
||||
const tdStringPtr = await __newString(blockData.td);
|
||||
const totalDifficulty = await BigInt.fromString(tdStringPtr);
|
||||
|
||||
const unclesHashPtr = await Bytes.empty();
|
||||
const authorPtr = await Address.zero();
|
||||
const gasUsedPtr = await BigInt.fromI32(0);
|
||||
const gasLimitPtr = await BigInt.fromI32(0);
|
||||
const difficultyPtr = await BigInt.fromI32(0);
|
||||
|
||||
// Missing fields from watcher in block data:
|
||||
// unclesHash
|
||||
@ -263,16 +300,16 @@ export const createBlock = async (instanceExports: any, blockData: Block): Promi
|
||||
return await ethereum.Block.__new(
|
||||
blockHash,
|
||||
parentHash,
|
||||
await Bytes.empty(),
|
||||
await Address.zero(),
|
||||
unclesHashPtr,
|
||||
authorPtr,
|
||||
stateRoot,
|
||||
transactionsRoot,
|
||||
receiptsRoot,
|
||||
blockNumber,
|
||||
await BigInt.fromI32(0),
|
||||
await BigInt.fromI32(0),
|
||||
gasUsedPtr,
|
||||
gasLimitPtr,
|
||||
blockTimestamp,
|
||||
await BigInt.fromI32(0),
|
||||
difficultyPtr,
|
||||
totalDifficulty,
|
||||
null
|
||||
);
|
||||
@ -286,109 +323,163 @@ export const getSubgraphConfig = async (subgraphPath: string): Promise<any> => {
|
||||
throw new Error(`Config file not found: ${configFilePath}`);
|
||||
}
|
||||
|
||||
const config = yaml.load(await fs.readFile(configFilePath, 'utf8'));
|
||||
const configFile = await fs.readFile(configFilePath, 'utf8');
|
||||
const config = yaml.load(configFile);
|
||||
log('config', JSON.stringify(config, null, 2));
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
export const toEntityValue = async (instanceExports: any, entityInstance: any, data: any, type: string, key: string) => {
|
||||
const { __newString, BigInt: ExportBigInt, Value, ByteArray, Bytes, BigDecimal } = instanceExports;
|
||||
export const toEntityValue = async (instanceExports: any, entityInstance: any, data: any, field: ColumnMetadata) => {
|
||||
const { __newString, Value } = instanceExports;
|
||||
const { type, isArray, propertyName } = field;
|
||||
|
||||
const entityKey = await __newString(propertyName);
|
||||
const entityValuePtr = await entityInstance.get(entityKey);
|
||||
const subgraphValue = Value.wrap(entityValuePtr);
|
||||
const value = data[propertyName];
|
||||
|
||||
const entityValue = await formatEntityValue(instanceExports, subgraphValue, type, value, isArray);
|
||||
|
||||
return entityInstance.set(entityKey, entityValue);
|
||||
};
|
||||
|
||||
export const fromEntityValue = async (instanceExports: any, entityInstance: any, key: string): Promise<any> => {
|
||||
const { __newString } = instanceExports;
|
||||
const entityKey = await __newString(key);
|
||||
const value = data[key];
|
||||
const entityValuePtr = await entityInstance.get(entityKey);
|
||||
|
||||
return parseEntityValue(instanceExports, entityValuePtr);
|
||||
};
|
||||
|
||||
const parseEntityValue = async (instanceExports: any, valuePtr: number) => {
|
||||
const {
|
||||
__getString,
|
||||
__getArray,
|
||||
BigInt: ExportBigInt,
|
||||
Bytes,
|
||||
BigDecimal,
|
||||
Value
|
||||
} = instanceExports;
|
||||
|
||||
const value = Value.wrap(valuePtr);
|
||||
const kind = await value.kind;
|
||||
|
||||
switch (kind) {
|
||||
case ValueKind.STRING: {
|
||||
const stringValue = await value.toString();
|
||||
return __getString(stringValue);
|
||||
}
|
||||
|
||||
case ValueKind.BYTES: {
|
||||
const bytesPtr = await value.toBytes();
|
||||
const bytes = await Bytes.wrap(bytesPtr);
|
||||
const bytesStringPtr = await bytes.toHexString();
|
||||
|
||||
return __getString(bytesStringPtr);
|
||||
}
|
||||
|
||||
case ValueKind.BOOL: {
|
||||
const bool = await value.toBoolean();
|
||||
|
||||
return Boolean(bool);
|
||||
}
|
||||
|
||||
case ValueKind.INT: {
|
||||
return value.toI32();
|
||||
}
|
||||
|
||||
case ValueKind.BIGINT: {
|
||||
const bigIntPtr = await value.toBigInt();
|
||||
const bigInt = ExportBigInt.wrap(bigIntPtr);
|
||||
const bigIntStringPtr = await bigInt.toString();
|
||||
const bigIntString = __getString(bigIntStringPtr);
|
||||
|
||||
return BigInt(bigIntString);
|
||||
}
|
||||
|
||||
case ValueKind.BIGDECIMAL: {
|
||||
const bigDecimalPtr = await value.toBigDecimal();
|
||||
const bigDecimal = BigDecimal.wrap(bigDecimalPtr);
|
||||
const bigDecimalStringPtr = await bigDecimal.toString();
|
||||
|
||||
return new Decimal(__getString(bigDecimalStringPtr));
|
||||
}
|
||||
|
||||
case ValueKind.ARRAY: {
|
||||
const arrayPtr = await value.toArray();
|
||||
const arr = await __getArray(arrayPtr);
|
||||
const arrDataPromises = arr.map((arrValuePtr: any) => parseEntityValue(instanceExports, arrValuePtr));
|
||||
|
||||
return Promise.all(arrDataPromises);
|
||||
}
|
||||
|
||||
case ValueKind.NULL: {
|
||||
return null;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported value kind: ${kind}`);
|
||||
}
|
||||
};
|
||||
|
||||
const formatEntityValue = async (instanceExports: any, subgraphValue: any, type: ColumnType, value: any, isArray: boolean): Promise<any> => {
|
||||
const { __newString, __newArray, BigInt: ExportBigInt, Value, ByteArray, Bytes, BigDecimal, id_of_type: getIdOfType } = instanceExports;
|
||||
|
||||
if (isArray) {
|
||||
// TODO: Implement handling array of Bytes type field.
|
||||
const dataArrayPromises = value.map((el: any) => formatEntityValue(instanceExports, subgraphValue, type, el, false));
|
||||
const dataArray = await Promise.all(dataArrayPromises);
|
||||
const arrayStoreValueId = await getIdOfType(TypeId.ArrayStoreValue);
|
||||
const valueArray = await __newArray(arrayStoreValueId, dataArray);
|
||||
|
||||
return Value.fromArray(valueArray);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'varchar': {
|
||||
const entityValue = await __newString(value);
|
||||
|
||||
const graphValue = Value.wrap(await entityInstance.get(entityKey));
|
||||
|
||||
const kind = await graphValue.kind;
|
||||
const kind = await subgraphValue.kind;
|
||||
|
||||
switch (kind) {
|
||||
case ValueKind.BYTES: {
|
||||
const byteArray = await ByteArray.fromHexString(entityValue);
|
||||
const bytes = await Bytes.fromByteArray(byteArray);
|
||||
return entityInstance.setBytes(entityKey, bytes);
|
||||
|
||||
return Value.fromBytes(bytes);
|
||||
}
|
||||
|
||||
default:
|
||||
return entityInstance.setString(entityKey, entityValue);
|
||||
return Value.fromString(entityValue);
|
||||
}
|
||||
}
|
||||
|
||||
case 'integer': {
|
||||
return entityInstance.setI32(entityKey, value);
|
||||
return Value.fromI32(value);
|
||||
}
|
||||
|
||||
case 'bigint': {
|
||||
const bigInt = await ExportBigInt.fromString(await __newString(value.toString()));
|
||||
const valueStringPtr = await __newString(value.toString());
|
||||
const bigInt = await ExportBigInt.fromString(valueStringPtr);
|
||||
|
||||
return entityInstance.setBigInt(entityKey, bigInt);
|
||||
return Value.fromBigInt(bigInt);
|
||||
}
|
||||
|
||||
case 'boolean': {
|
||||
return entityInstance.setBoolean(entityKey, value ? 1 : 0);
|
||||
return Value.fromBoolean(value ? 1 : 0);
|
||||
}
|
||||
|
||||
case 'enum': {
|
||||
const entityValue = await __newString(value);
|
||||
return entityInstance.setString(entityKey, entityValue);
|
||||
|
||||
return Value.fromString(entityValue);
|
||||
}
|
||||
|
||||
case 'numeric': {
|
||||
const bigDecimal = await BigDecimal.fromString(await __newString(value.toString()));
|
||||
return entityInstance.setBigDecimal(entityKey, bigDecimal);
|
||||
}
|
||||
const valueStringPtr = await __newString(value.toString());
|
||||
const bigDecimal = await BigDecimal.fromString(valueStringPtr);
|
||||
|
||||
// TODO: Support more types.
|
||||
default:
|
||||
throw new Error(`Unsupported type: ${type}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const fromEntityValue = async (instanceExports: any, entityInstance: any, type: string, key: string): Promise<any> => {
|
||||
const { __newString, __getString, BigInt: ExportBigInt, Value, BigDecimal, Bytes } = instanceExports;
|
||||
const entityKey = await __newString(key);
|
||||
|
||||
switch (type) {
|
||||
case 'varchar': {
|
||||
const value = Value.wrap(await entityInstance.get(entityKey));
|
||||
|
||||
const kind = await value.kind;
|
||||
|
||||
switch (kind) {
|
||||
case ValueKind.BYTES: {
|
||||
const bytes = await Bytes.wrap(await value.toBytes());
|
||||
const bytesStringPtr = await bytes.toHexString();
|
||||
return __getString(bytesStringPtr);
|
||||
}
|
||||
|
||||
default:
|
||||
return __getString(await entityInstance.getString(entityKey));
|
||||
}
|
||||
}
|
||||
|
||||
case 'integer': {
|
||||
return entityInstance.getI32(entityKey);
|
||||
}
|
||||
|
||||
case 'bigint': {
|
||||
const bigInt = ExportBigInt.wrap(await entityInstance.getBigInt(entityKey));
|
||||
return BigInt(__getString(await bigInt.toString()));
|
||||
}
|
||||
|
||||
case 'boolean': {
|
||||
return Boolean(await entityInstance.getBoolean(entityKey));
|
||||
}
|
||||
|
||||
case 'enum': {
|
||||
return __getString(await entityInstance.getString(entityKey));
|
||||
}
|
||||
|
||||
case 'numeric': {
|
||||
const bigDecimal = BigDecimal.wrap(await entityInstance.getBigDecimal(entityKey));
|
||||
return new Decimal(__getString(await bigDecimal.toString()));
|
||||
return Value.fromBigDecimal(bigDecimal);
|
||||
}
|
||||
|
||||
// TODO: Support more types.
|
||||
|
@ -12,6 +12,70 @@ import {
|
||||
BigDecimal
|
||||
} from "@graphprotocol/graph-ts";
|
||||
|
||||
export class RelatedEntity extends Entity {
|
||||
constructor(id: string) {
|
||||
super();
|
||||
this.set("id", Value.fromString(id));
|
||||
|
||||
this.set("paramBigInt", Value.fromBigInt(BigInt.zero()));
|
||||
this.set("examples", Value.fromStringArray(new Array(0)));
|
||||
this.set("bigIntArray", Value.fromBigIntArray(new Array(0)));
|
||||
}
|
||||
|
||||
save(): void {
|
||||
let id = this.get("id");
|
||||
assert(id != null, "Cannot save RelatedEntity entity without an ID");
|
||||
if (id) {
|
||||
assert(
|
||||
id.kind == ValueKind.STRING,
|
||||
"Cannot save RelatedEntity entity with non-string ID. " +
|
||||
'Considering using .toHex() to convert the "id" to a string.'
|
||||
);
|
||||
store.set("RelatedEntity", id.toString(), this);
|
||||
}
|
||||
}
|
||||
|
||||
static load(id: string): RelatedEntity | null {
|
||||
return changetype<RelatedEntity | null>(store.get("RelatedEntity", id));
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
let value = this.get("id");
|
||||
return value!.toString();
|
||||
}
|
||||
|
||||
set id(value: string) {
|
||||
this.set("id", Value.fromString(value));
|
||||
}
|
||||
|
||||
get paramBigInt(): BigInt {
|
||||
let value = this.get("paramBigInt");
|
||||
return value!.toBigInt();
|
||||
}
|
||||
|
||||
set paramBigInt(value: BigInt) {
|
||||
this.set("paramBigInt", Value.fromBigInt(value));
|
||||
}
|
||||
|
||||
get examples(): Array<string> {
|
||||
let value = this.get("examples");
|
||||
return value!.toStringArray();
|
||||
}
|
||||
|
||||
set examples(value: Array<string>) {
|
||||
this.set("examples", Value.fromStringArray(value));
|
||||
}
|
||||
|
||||
get bigIntArray(): Array<BigInt> {
|
||||
let value = this.get("bigIntArray");
|
||||
return value!.toBigIntArray();
|
||||
}
|
||||
|
||||
set bigIntArray(value: Array<BigInt>) {
|
||||
this.set("bigIntArray", Value.fromBigIntArray(value));
|
||||
}
|
||||
}
|
||||
|
||||
export class ExampleEntity extends Entity {
|
||||
constructor(id: string) {
|
||||
super();
|
||||
@ -24,6 +88,7 @@ export class ExampleEntity extends Entity {
|
||||
this.set("paramBytes", Value.fromBytes(Bytes.empty()));
|
||||
this.set("paramEnum", Value.fromString(""));
|
||||
this.set("paramBigDecimal", Value.fromBigDecimal(BigDecimal.zero()));
|
||||
this.set("related", Value.fromString(""));
|
||||
}
|
||||
|
||||
save(): void {
|
||||
@ -114,4 +179,13 @@ export class ExampleEntity extends Entity {
|
||||
set paramBigDecimal(value: BigDecimal) {
|
||||
this.set("paramBigDecimal", Value.fromBigDecimal(value));
|
||||
}
|
||||
|
||||
get related(): string {
|
||||
let value = this.get("related");
|
||||
return value!.toString();
|
||||
}
|
||||
|
||||
set related(value: string) {
|
||||
this.set("related", Value.fromString(value));
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,13 @@ enum EnumType {
|
||||
choice2
|
||||
}
|
||||
|
||||
type RelatedEntity @entity {
|
||||
id: ID!
|
||||
paramBigInt: BigInt!
|
||||
examples: [ExampleEntity!]!
|
||||
bigIntArray: [BigInt!]!
|
||||
}
|
||||
|
||||
type ExampleEntity @entity {
|
||||
id: ID!
|
||||
count: BigInt!
|
||||
@ -12,4 +19,5 @@ type ExampleEntity @entity {
|
||||
paramBytes: Bytes!
|
||||
paramEnum: EnumType!
|
||||
paramBigDecimal: BigDecimal!
|
||||
related: RelatedEntity!
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
Example1,
|
||||
Test
|
||||
} from '../generated/Example1/Example1';
|
||||
import { ExampleEntity } from '../generated/schema';
|
||||
import { ExampleEntity, RelatedEntity } from '../generated/schema';
|
||||
|
||||
export function handleTest (event: Test): void {
|
||||
log.debug('event.address: {}', [event.address.toHexString()]);
|
||||
@ -15,12 +15,12 @@ export function handleTest (event: Test): void {
|
||||
|
||||
// Entities can be loaded from the store using a string ID; this ID
|
||||
// needs to be unique across all entities of the same type
|
||||
let entity = ExampleEntity.load(event.transaction.from.toHex());
|
||||
let entity = ExampleEntity.load(event.transaction.hash.toHexString());
|
||||
|
||||
// Entities only exist after they have been saved to the store;
|
||||
// `null` checks allow to create entities on demand
|
||||
if (!entity) {
|
||||
entity = new ExampleEntity(event.transaction.from.toHex());
|
||||
entity = new ExampleEntity(event.transaction.hash.toHexString());
|
||||
|
||||
// Entity fields can be set using simple assignments
|
||||
entity.count = BigInt.fromString('0');
|
||||
@ -37,6 +37,25 @@ export function handleTest (event: Test): void {
|
||||
entity.paramEnum = 'choice1';
|
||||
entity.paramBigDecimal = BigDecimal.fromString('123');
|
||||
|
||||
let relatedEntity = RelatedEntity.load(event.transaction.from.toHex());
|
||||
|
||||
if (!relatedEntity) {
|
||||
relatedEntity = new RelatedEntity(event.transaction.from.toHex());
|
||||
relatedEntity.paramBigInt = BigInt.fromString('123');
|
||||
}
|
||||
|
||||
const bigIntArray = relatedEntity.bigIntArray;
|
||||
bigIntArray.push(entity.count);
|
||||
relatedEntity.bigIntArray = bigIntArray;
|
||||
|
||||
const examples = relatedEntity.examples;
|
||||
examples.push(entity.id);
|
||||
relatedEntity.examples = examples;
|
||||
|
||||
relatedEntity.save();
|
||||
|
||||
entity.related = relatedEntity.id;
|
||||
|
||||
// Entities can be written to the store with `.save()`
|
||||
entity.save();
|
||||
|
||||
|
@ -47,4 +47,7 @@ export class ExampleEntity {
|
||||
|
||||
@Column('numeric', { default: 0, transformer: decimalTransformer })
|
||||
paramBigDecimal!: Decimal
|
||||
|
||||
@Column('varchar')
|
||||
related!: string;
|
||||
}
|
||||
|
28
packages/graph-test-watcher/src/entity/RelatedEntity.ts
Normal file
28
packages/graph-test-watcher/src/entity/RelatedEntity.ts
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright 2021 Vulcanize, Inc.
|
||||
//
|
||||
|
||||
import { Entity, PrimaryColumn, Column } from 'typeorm';
|
||||
|
||||
import { bigintTransformer, bigintArrayTransformer } from '@vulcanize/util';
|
||||
|
||||
@Entity()
|
||||
export class RelatedEntity {
|
||||
@PrimaryColumn('varchar')
|
||||
id!: string;
|
||||
|
||||
@PrimaryColumn('varchar', { length: 66 })
|
||||
blockHash!: string;
|
||||
|
||||
@Column('integer')
|
||||
blockNumber!: number;
|
||||
|
||||
@Column('bigint', { transformer: bigintTransformer })
|
||||
paramBigInt!: bigint;
|
||||
|
||||
@Column('varchar', { array: true })
|
||||
examples!: string[];
|
||||
|
||||
@Column('bigint', { transformer: bigintArrayTransformer, array: true })
|
||||
bigIntArray!: bigint[];
|
||||
}
|
@ -77,11 +77,21 @@ type Query {
|
||||
getState(blockHash: String!, contractAddress: String!, kind: String): ResultIPLDBlock
|
||||
}
|
||||
|
||||
enum EnumType {
|
||||
choice1
|
||||
choice2
|
||||
}
|
||||
|
||||
type ExampleEntity {
|
||||
id: ID!
|
||||
count: BigInt!
|
||||
param1: String!
|
||||
param2: Int!
|
||||
paramString: String!
|
||||
paramInt: Int!
|
||||
paramBoolean: Boolean!
|
||||
paramBytes: Bytes!
|
||||
paramEnum: EnumType!
|
||||
paramBigDecimal: BigDecimal!
|
||||
related: String!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
|
@ -80,6 +80,40 @@ export const bigintTransformer: ValueTransformer = {
|
||||
}
|
||||
};
|
||||
|
||||
export const bigintArrayTransformer: ValueTransformer = {
|
||||
to: (valueArray?: bigint[]) => {
|
||||
if (valueArray) {
|
||||
return valueArray.map(value => bigintTransformer.to(value));
|
||||
}
|
||||
|
||||
return valueArray;
|
||||
},
|
||||
from: (valueArray?: string[]) => {
|
||||
if (valueArray) {
|
||||
return valueArray.map(value => bigintTransformer.from(value));
|
||||
}
|
||||
|
||||
return valueArray;
|
||||
}
|
||||
};
|
||||
|
||||
export const decimalArrayTransformer: ValueTransformer = {
|
||||
to: (valueArray?: Decimal[]) => {
|
||||
if (valueArray) {
|
||||
return valueArray.map(value => decimalTransformer.to(value));
|
||||
}
|
||||
|
||||
return valueArray;
|
||||
},
|
||||
from: (valueArray?: string[]) => {
|
||||
if (valueArray) {
|
||||
return valueArray.map(value => decimalTransformer.from(value));
|
||||
}
|
||||
|
||||
return valueArray;
|
||||
}
|
||||
};
|
||||
|
||||
export const resetJobs = async (config: Config): Promise<void> => {
|
||||
const { jobQueue: jobQueueConfig } = config;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user