import '../common/eager_offset' import { Bytes, Wrapped } from '../common/collections' import { Address, BigInt } from '../common/numbers' /** Host Ethereum interface */ export declare namespace ethereum { function call(call: SmartContractCall): Array | null function encode(token: Value): Bytes | null function decode(types: String, data: Bytes): Value | null } export namespace ethereum { /** Type hint for Ethereum values. */ export enum ValueKind { ADDRESS = 0, FIXED_BYTES = 1, BYTES = 2, INT = 3, UINT = 4, BOOL = 5, STRING = 6, FIXED_ARRAY = 7, ARRAY = 8, TUPLE = 9, } /** * Pointer type for Ethereum value data. * * Big enough to fit any pointer or native `this.data`. */ export type ValuePayload = u64 /** * A dynamically typed value used when accessing Ethereum data. */ export class Value { constructor(public kind: ValueKind, public data: ValuePayload) {} @operator('<') lt(other: Value): boolean { abort("Less than operator isn't supported in Value") return false } @operator('>') gt(other: Value): boolean { abort("Greater than operator isn't supported in Value") return false } toAddress(): Address { assert(this.kind == ValueKind.ADDRESS, 'Ethereum value is not an address') return changetype
(this.data as u32) } toBoolean(): boolean { assert(this.kind == ValueKind.BOOL, 'Ethereum value is not a boolean.') return this.data != 0 } toBytes(): Bytes { assert( this.kind == ValueKind.FIXED_BYTES || this.kind == ValueKind.BYTES, 'Ethereum value is not bytes.', ) return changetype(this.data as u32) } toI32(): i32 { assert( this.kind == ValueKind.INT || this.kind == ValueKind.UINT, 'Ethereum value is not an int or uint.', ) let bigInt = changetype(this.data as u32) return bigInt.toI32() } toBigInt(): BigInt { assert( this.kind == ValueKind.INT || this.kind == ValueKind.UINT, 'Ethereum value is not an int or uint.', ) return changetype(this.data as u32) } toString(): string { assert(this.kind == ValueKind.STRING, 'Ethereum value is not a string.') return changetype(this.data as u32) } toArray(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array.', ) return changetype>(this.data as u32) } toTuple(): Tuple { assert(this.kind == ValueKind.TUPLE, 'Ethereum value is not a tuple.') return changetype(this.data as u32) } toTupleArray(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array.', ) let valueArray = this.toArray() let out = new Array(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = changetype(valueArray[i].toTuple()) } return out } toBooleanArray(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array or fixed array.', ) let valueArray = this.toArray() let out = new Array(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = valueArray[i].toBoolean() } return out } toBytesArray(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array or fixed array.', ) let valueArray = this.toArray() let out = new Array(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = valueArray[i].toBytes() } return out } toAddressArray(): Array
{ assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array or fixed array.', ) let valueArray = this.toArray() let out = new Array
(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = valueArray[i].toAddress() } return out } toStringArray(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array or fixed array.', ) let valueArray = this.toArray() let out = new Array(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = valueArray[i].toString() } return out } toI32Array(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array or fixed array.', ) let valueArray = this.toArray() let out = new Array(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = valueArray[i].toI32() } return out } toBigIntArray(): Array { assert( this.kind == ValueKind.ARRAY || this.kind == ValueKind.FIXED_ARRAY, 'Ethereum value is not an array or fixed array.', ) let valueArray = this.toArray() let out = new Array(valueArray.length) for (let i: i32 = 0; i < valueArray.length; i++) { out[i] = valueArray[i].toBigInt() } return out } static fromAddress(address: Address): Value { assert(address.length == 20, 'Address must contain exactly 20 bytes') return new Value(ValueKind.ADDRESS, changetype(address)) } static fromBoolean(b: boolean): Value { return new Value(ValueKind.BOOL, b ? 1 : 0) } static fromBytes(bytes: Bytes): Value { return new Value(ValueKind.BYTES, changetype(bytes)) } static fromFixedBytes(bytes: Bytes): Value { return new Value(ValueKind.FIXED_BYTES, changetype(bytes)) } static fromI32(i: i32): Value { return new Value(ValueKind.INT, changetype(BigInt.fromI32(i))) } static fromSignedBigInt(i: BigInt): Value { return new Value(ValueKind.INT, changetype(i)) } static fromUnsignedBigInt(i: BigInt): Value { return new Value(ValueKind.UINT, changetype(i)) } static fromString(s: string): Value { return new Value(ValueKind.STRING, changetype(s)) } static fromArray(values: Array): Value { return new Value(ValueKind.ARRAY, changetype(values)) } static fromFixedSizedArray(values: Array): Value { return new Value(ValueKind.FIXED_ARRAY, changetype(values)) } static fromTuple(values: Tuple): Value { return new Value(ValueKind.TUPLE, changetype(values)) } static fromTupleArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromTuple(values[i]) } return Value.fromArray(out) } static fromBooleanArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromBoolean(values[i]) } return Value.fromArray(out) } static fromBytesArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromBytes(values[i]) } return Value.fromArray(out) } static fromFixedBytesArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromFixedBytes(values[i]) } return Value.fromArray(out) } static fromAddressArray(values: Array
): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromAddress(values[i]) } return Value.fromArray(out) } static fromStringArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromString(values[i]) } return Value.fromArray(out) } static fromI32Array(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromI32(values[i]) } return Value.fromArray(out) } static fromSignedBigIntArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromSignedBigInt(values[i]) } return Value.fromArray(out) } static fromUnsignedBigIntArray(values: Array): Value { let out = new Array(values.length) for (let i: i32 = 0; i < values.length; i++) { out[i] = Value.fromUnsignedBigInt(values[i]) } return Value.fromArray(out) } } /** * Common representation for Ethereum tuples / Solidity structs. * * This base class stores the tuple/struct values in an array. The Graph CLI * code generation then creates subclasses that provide named getters to * access the members by name. */ export class Tuple extends Array {} /** * An Ethereum block. */ export class Block { constructor( public hash: Bytes, public parentHash: Bytes, public unclesHash: Bytes, public author: Address, public stateRoot: Bytes, public transactionsRoot: Bytes, public receiptsRoot: Bytes, public number: BigInt, public gasUsed: BigInt, public gasLimit: BigInt, public timestamp: BigInt, public difficulty: BigInt, public totalDifficulty: BigInt, public size: BigInt | null, public baseFeePerGas: BigInt | null, ) {} } /** * An Ethereum transaction. */ export class Transaction { constructor( public hash: Bytes, public index: BigInt, public from: Address, public to: Address | null, public value: BigInt, public gasLimit: BigInt, public gasPrice: BigInt, public input: Bytes, public nonce: BigInt, ) {} } /** * An Ethereum transaction receipt. */ export class TransactionReceipt { constructor( public transactionHash: Bytes, public transactionIndex: BigInt, public blockHash: Bytes, public blockNumber: BigInt, public cumulativeGasUsed: BigInt, public gasUsed: BigInt, public contractAddress: Address, public logs: Array, public status: BigInt, public root: Bytes, public logsBloom: Bytes, ) {} } /** * An Ethereum event log. */ export class Log { constructor( public address: Address, public topics: Array, public data: Bytes, public blockHash: Bytes, public blockNumber: Bytes, public transactionHash: Bytes, public transactionIndex: BigInt, public logIndex: BigInt, public transactionLogIndex: BigInt, public logType: string, public removed: Wrapped | null, ) {} } /** * Common representation for Ethereum smart contract calls. */ export class Call { constructor( public to: Address, public from: Address, public block: Block, public transaction: Transaction, public inputValues: Array, public outputValues: Array, ) {} } /** * Common representation for Ethereum smart contract events. */ export class Event { constructor( public address: Address, public logIndex: BigInt, public transactionLogIndex: BigInt, public logType: string | null, public block: Block, public transaction: Transaction, public parameters: Array, public receipt: TransactionReceipt | null, ) {} } /** * A dynamically-typed Ethereum event parameter. */ export class EventParam { constructor(public name: string, public value: Value) {} } export class SmartContractCall { contractName: string contractAddress: Address functionName: string functionSignature: string functionParams: Array constructor( contractName: string, contractAddress: Address, functionName: string, functionSignature: string, functionParams: Array, ) { this.contractName = contractName this.contractAddress = contractAddress this.functionName = functionName this.functionSignature = functionSignature this.functionParams = functionParams } } /** * Low-level interaction with Ethereum smart contracts */ export class SmartContract { _name: string _address: Address protected constructor(name: string, address: Address) { this._name = name this._address = address } call(name: string, signature: string, params: Array): Array { let call = new SmartContractCall(this._name, this._address, name, signature, params) let result = ethereum.call(call) assert( result != null, 'Call reverted, probably because an `assert` or `require` in the contract failed, ' + 'consider using `try_' + name + '` to handle this in the mapping.', ) return changetype>(result) } tryCall( name: string, signature: string, params: Array, ): CallResult> { let call = new SmartContractCall(this._name, this._address, name, signature, params) let result = ethereum.call(call) if (result == null) { return new CallResult() } else { return CallResult.fromValue(changetype>(result)) } } } export class CallResult { // `null` indicates a reverted call. private _value: Wrapped | null constructor() { this._value = null } static fromValue(value: T): CallResult { let result = new CallResult() result._value = new Wrapped(value) return result } get reverted(): bool { return this._value == null } get value(): T { assert( !this.reverted, 'accessed value of a reverted call, ' + 'please check the `reverted` field before accessing the `value` field', ) return changetype>(this._value).inner } } }