diff --git a/e2e_support/genesis.json b/e2e_support/genesis.json index f457c767..1d859bf0 100644 --- a/e2e_support/genesis.json +++ b/e2e_support/genesis.json @@ -39,6 +39,10 @@ "name": "auth:sigtx:eth", "status": "WAITING" }, + { + "name": "auth:sigtx:eth0", + "status": "WAITING" + }, { "name": "auth:sigtx:eth1", "status": "WAITING" @@ -78,6 +82,10 @@ { "name": "evm:constantinople", "status": "WAITING" + }, + { + "name": "tx:eth", + "status": "WAITING" } ] } diff --git a/e2e_support/loom.yaml b/e2e_support/loom.yaml index ceb1dcff..b45c2c6f 100644 --- a/e2e_support/loom.yaml +++ b/e2e_support/loom.yaml @@ -35,10 +35,10 @@ ChainConfig: ContractEnabled: true Auth: Chains: - eth: + eth1: TxType: "eth" AccountType: 1 - eth1: + eth0: TxType: "eth" AccountType: 0 tron: @@ -50,4 +50,4 @@ Auth: ContractLoaders: - "static" - "dynamic" - - "external" \ No newline at end of file + - "external" diff --git a/src/index.ts b/src/index.ts index 7df96883..865719c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,6 +25,7 @@ export { } from './middleware' export { createDefaultTxMiddleware } from './helpers' export { LoomProvider } from './loom-provider' +export { LoomProvider2 } from './loom-provider-2' import * as Contracts from './contracts' export { Contracts } diff --git a/src/loom-provider-2.ts b/src/loom-provider-2.ts new file mode 100644 index 00000000..e6fb2449 --- /dev/null +++ b/src/loom-provider-2.ts @@ -0,0 +1,275 @@ +import debug from 'debug' +import retry from 'retry' +import { Wallet } from 'ethers' +import { Client as WSClient } from 'rpc-websockets' +import { EthRPCMethod, IEthRPCPayload } from './loom-provider' +import { hexToNumber } from './crypto-utils' +import { EventEmitter } from 'events' + +const debugLog = debug('loom-provider-2') +const eventLog = debug('loom-provider-2:event') +const errorLog = debug('loom-provider-2:error') + +/** + * Web3 provider that interacts with EVM contracts deployed on Loom DAppChains. + */ +export class LoomProvider2 { + private _wallet: Wallet + private _wsRPC: WSClient + private _ethRPCMethods: Map = new Map() + protected notificationCallbacks: Array = new Array() + + /** + * The retry strategy that should be used to retry some web3 requests. + * By default failed requested won't be resent. + * To understand how to tweak the retry strategy see + * https://github.com/tim-kos/node-retry#retrytimeoutsoptions + */ + retryStrategy: retry.OperationOptions = { + retries: 0, + minTimeout: 1000, // 1s + maxTimeout: 30000, // 30s + randomize: true + } + + /** + * Constructs the LoomProvider2 to bridges communication between Web3 and Loom DappChains + * + * @param host Loomchain address + * @param ecdsaPrivateKey ECDSA private key + */ + constructor(public host: string, private ecdsaPrivateKey?: string) { + // Simply create socket + this._wsRPC = new WSClient(host) + + // If no privakey passed generate a random wallet + this._wallet = ecdsaPrivateKey ? new Wallet(ecdsaPrivateKey) : Wallet.createRandom() + + // Emits new messages to the provider handler above (Web3) + this._wsRPC.once('open', () => { + ;((this._wsRPC as any).socket as EventEmitter).on( + 'message', + this._onWebSocketMessage.bind(this) + ) + ;((this._wsRPC as any).socket as WebSocket).onclose = () => { + this.reset() + } + }) + + // Prepare LoomProvider2 default methods + this.addDefaultMethods() + } + + get wallet(): Wallet { + return this._wallet + } + + addDefaultMethods() { + this._ethRPCMethods.set('eth_accounts', this._ethAccounts.bind(this)) + this._ethRPCMethods.set('eth_sendTransaction', this._ethSendTransaction.bind(this)) + } + + // Adapter function for sendAsync from truffle provider + async sendAsync(payload: any, callback?: Function): Promise { + if (callback) { + await this.send(payload, callback) + } else { + return new Promise((resolve, reject) => { + this.send(payload, (err: Error, result: any) => { + if (err) reject(err) + else resolve(result) + }) + }) + } + } + + /** + * Should be used to make async request + * + * @param payload JSON payload + * @param callback Triggered on end with (err, result) + */ + async send(payload: any, callback: Function) { + const isArray = Array.isArray(payload) + if (isArray) { + payload = payload[0] + } + + debugLog('New Payload', JSON.stringify(payload, null, 2)) + + if (!this._wsRPC.ready) { + debugLog('Socket not ready resched call', payload) + + setTimeout(() => { + this.send(payload, callback) + }, 1000) + + return + } + + const op = retry.operation(this.retryStrategy) + op.attempt(async currAttempt => { + debugLog(`Current attempt ${currAttempt}`) + + let result + + try { + if (this._ethRPCMethods.has(payload.method)) { + const f: Function = this._ethRPCMethods.get(payload.method)! + result = await f(payload) + } else { + result = await this._wsRPC.call(payload.method, payload.params) + } + + callback(null, this._okResponse(payload.id, result, isArray)) + } catch (err) { + if (!op.retry(err)) { + callback(err, null) + } else { + errorLog(err) + } + } + }) + } + + // EVENT HANDLING METHODS + + on(type: string, callback: any) { + if (typeof callback !== 'function') { + throw new Error('The second parameter callback must be a function.') + } + + eventLog('On event', type) + + switch (type) { + case 'data': + this.notificationCallbacks.push(callback) + break + case 'connect': + ;((this._wsRPC as any).socket as WebSocket).onopen = callback + break + case 'end': + ;((this._wsRPC as any).socket as WebSocket).onclose = callback + break + case 'error': + ;((this._wsRPC as any).socket as WebSocket).onerror = callback + break + } + } + + removeListener(type: string, callback: (...args: any[]) => void) { + eventLog('Remove listner', type) + + switch (type) { + case 'data': + this.notificationCallbacks.forEach((cb, index) => { + if (cb === callback) { + this.notificationCallbacks.splice(index, 1) + } + }) + break + } + } + + removeAllListeners(type: string) { + eventLog('Remove all listeners of type', type) + + switch (type) { + case 'data': + this.notificationCallbacks = [] + break + case 'connect': + ;((this._wsRPC as any).socket as WebSocket).onopen = null + break + case 'end': + ;((this._wsRPC as any).socket as WebSocket).onclose = null + break + case 'error': + ;((this._wsRPC as any).socket as WebSocket).onerror = null + break + } + } + + reset() { + eventLog('Reset notifications') + this.notificationCallbacks = [] + } + + disconnect() { + debugLog(`Disconnect`) + this._wsRPC.close(1000, 'bye') + } + + // PRIVATE FUNCTIONS + + private async _ethAccounts() { + const address = await this.wallet.getAddress() + return [address] + } + + private async _ethSendTransaction(payload: IEthRPCPayload) { + const params: any = payload.params[0] + + const account = await this.wallet.getAddress() + + // Get the nonce for the next tx + const nonce = await this.sendAsync({ + id: 0, + method: 'eth_getTransactionCount', + params: [account, 'latest'] + }) + + debugLog(`Next nonce ${nonce.result}`) + + // Create transaction + const transaction: any = { + nonce: hexToNumber(nonce.result) + 1, + data: params.data, + gasPrice: '0x0' + } + + if (params.to) { + transaction.to = params.to + } + + if (params.value) { + transaction.value = params.value + } + + const signedTransaction = await this.wallet.sign(transaction) + + debugLog(`Signed transaction ${JSON.stringify(transaction, null, 2)} ${signedTransaction}`) + + const tx = await this.sendAsync({ + id: 0, + method: 'eth_sendRawTransaction', + params: [signedTransaction] + }) + + return tx.result + } + + private _onWebSocketMessage(jsonResult: any) { + try { + const result = JSON.parse(jsonResult) + + if (result && result.method && result.method.indexOf('_subscription') !== -1) { + eventLog('New socket event', jsonResult) + + this.notificationCallbacks.forEach((callback: Function) => { + callback(result) + }) + } + } catch (err) { + errorLog(err) + } + } + + // Basic response to web3js + private _okResponse(id: number, result: any = 0, isArray: boolean = false): any { + const response = { id, jsonrpc: '2.0', result } + const ret = isArray ? [response] : response + debugLog('Response payload', JSON.stringify(ret, null, 2)) + return ret + } +} diff --git a/src/mainnet-contracts/ERC20Gateway.d.ts b/src/mainnet-contracts/ERC20Gateway.d.ts new file mode 100644 index 00000000..1b8b7d02 --- /dev/null +++ b/src/mainnet-contracts/ERC20Gateway.d.ts @@ -0,0 +1,249 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, ContractTransaction, EventFilter, Signer } from "ethers"; +import { Listener, Provider } from "ethers/providers"; +import { Arrayish, BigNumber, BigNumberish, Interface } from "ethers/utils"; +import { + TransactionOverrides, + TypedEventDescription, + TypedFunctionDescription +} from "."; + +interface ERC20GatewayInterface extends Interface { + functions: { + toggleToken: TypedFunctionDescription<{ + encode([_token]: [string]): string; + }>; + + renounceOwnership: TypedFunctionDescription<{ encode([]: []): string }>; + + addValidator: TypedFunctionDescription<{ + encode([_validator, _v, _r, _s]: [ + string, + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + removeValidator: TypedFunctionDescription<{ + encode([_validator, _v, _r, _s]: [ + string, + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + transferOwnership: TypedFunctionDescription<{ + encode([_newOwner]: [string]): string; + }>; + + withdrawERC20: TypedFunctionDescription<{ + encode([amount, sig, contractAddress]: [ + BigNumberish, + Arrayish, + string + ]): string; + }>; + + depositERC20: TypedFunctionDescription<{ + encode([amount, contractAddress]: [BigNumberish, string]): string; + }>; + + toggleAllowAnyToken: TypedFunctionDescription<{ + encode([_allow]: [boolean]): string; + }>; + }; + + events: { + ERC20Received: TypedEventDescription<{ + encodeTopics([from, amount, contractAddress]: [ + null, + null, + null + ]): string[]; + }>; + + TokenWithdrawn: TypedEventDescription<{ + encodeTopics([owner, kind, contractAddress, value]: [ + string | null, + null, + null, + null + ]): string[]; + }>; + + LoomCoinReceived: TypedEventDescription<{ + encodeTopics([from, amount, loomCoinAddress]: [ + string | null, + null, + null + ]): string[]; + }>; + + AddedValidator: TypedEventDescription<{ + encodeTopics([validator]: [null]): string[]; + }>; + + RemovedValidator: TypedEventDescription<{ + encodeTopics([validator]: [null]): string[]; + }>; + + OwnershipRenounced: TypedEventDescription<{ + encodeTopics([previousOwner]: [string | null]): string[]; + }>; + + OwnershipTransferred: TypedEventDescription<{ + encodeTopics([previousOwner, newOwner]: [ + string | null, + string | null + ]): string[]; + }>; + }; +} + +export class ERC20Gateway extends Contract { + connect(signerOrProvider: Signer | Provider | string): ERC20Gateway; + attach(addressOrName: string): ERC20Gateway; + deployed(): Promise; + + on(event: EventFilter | string, listener: Listener): ERC20Gateway; + once(event: EventFilter | string, listener: Listener): ERC20Gateway; + addListener( + eventName: EventFilter | string, + listener: Listener + ): ERC20Gateway; + removeAllListeners(eventName: EventFilter | string): ERC20Gateway; + removeListener(eventName: any, listener: Listener): ERC20Gateway; + + interface: ERC20GatewayInterface; + + functions: { + checkValidator(_address: string): Promise; + + nonces(arg0: string): Promise; + + allowedTokens(arg0: string): Promise; + + getERC20(contractAddress: string): Promise; + + toggleToken( + _token: string, + overrides?: TransactionOverrides + ): Promise; + + renounceOwnership( + overrides?: TransactionOverrides + ): Promise; + + addValidator( + _validator: string, + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + removeValidator( + _validator: string, + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + transferOwnership( + _newOwner: string, + overrides?: TransactionOverrides + ): Promise; + + withdrawERC20( + amount: BigNumberish, + sig: Arrayish, + contractAddress: string, + overrides?: TransactionOverrides + ): Promise; + + depositERC20( + amount: BigNumberish, + contractAddress: string, + overrides?: TransactionOverrides + ): Promise; + + toggleAllowAnyToken( + _allow: boolean, + overrides?: TransactionOverrides + ): Promise; + + loomAddress(): Promise; + numValidators(): Promise; + allowAnyToken(): Promise; + owner(): Promise; + nonce(): Promise; + }; + + filters: { + ERC20Received(from: null, amount: null, contractAddress: null): EventFilter; + + TokenWithdrawn( + owner: string | null, + kind: null, + contractAddress: null, + value: null + ): EventFilter; + + LoomCoinReceived( + from: string | null, + amount: null, + loomCoinAddress: null + ): EventFilter; + + AddedValidator(validator: null): EventFilter; + + RemovedValidator(validator: null): EventFilter; + + OwnershipRenounced(previousOwner: string | null): EventFilter; + + OwnershipTransferred( + previousOwner: string | null, + newOwner: string | null + ): EventFilter; + }; + + estimate: { + toggleToken(_token: string): Promise; + + renounceOwnership(): Promise; + + addValidator( + _validator: string, + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + removeValidator( + _validator: string, + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + transferOwnership(_newOwner: string): Promise; + + withdrawERC20( + amount: BigNumberish, + sig: Arrayish, + contractAddress: string + ): Promise; + + depositERC20( + amount: BigNumberish, + contractAddress: string + ): Promise; + + toggleAllowAnyToken(_allow: boolean): Promise; + }; +} diff --git a/src/mainnet-contracts/ERC20GatewayFactory.ts b/src/mainnet-contracts/ERC20GatewayFactory.ts new file mode 100644 index 00000000..623c5b95 --- /dev/null +++ b/src/mainnet-contracts/ERC20GatewayFactory.ts @@ -0,0 +1,455 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, Signer } from "ethers"; +import { Provider } from "ethers/providers"; + +import { ERC20Gateway } from "./ERC20Gateway"; + +export class ERC20GatewayFactory { + static connect( + address: string, + signerOrProvider: Signer | Provider + ): ERC20Gateway { + return new Contract(address, _abi, signerOrProvider) as ERC20Gateway; + } +} + +const _abi = [ + { + constant: false, + inputs: [ + { + name: "_token", + type: "address" + } + ], + name: "toggleToken", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [], + name: "loomAddress", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [], + name: "numValidators", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [], + name: "renounceOwnership", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "_address", + type: "address" + } + ], + name: "checkValidator", + outputs: [ + { + name: "", + type: "bool" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "address" + } + ], + name: "nonces", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [], + name: "allowAnyToken", + outputs: [ + { + name: "", + type: "bool" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [], + name: "owner", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_validator", + type: "address" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "addValidator", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [], + name: "nonce", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_validator", + type: "address" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "removeValidator", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "address" + } + ], + name: "allowedTokens", + outputs: [ + { + name: "", + type: "bool" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_newOwner", + type: "address" + } + ], + name: "transferOwnership", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + name: "_loomAddress", + type: "address" + }, + { + name: "_validators", + type: "address[]" + }, + { + name: "_threshold_num", + type: "uint8" + }, + { + name: "_threshold_denom", + type: "uint8" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "constructor" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + } + ], + name: "ERC20Received", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "owner", + type: "address" + }, + { + indexed: false, + name: "kind", + type: "uint8" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + }, + { + indexed: false, + name: "value", + type: "uint256" + } + ], + name: "TokenWithdrawn", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "loomCoinAddress", + type: "address" + } + ], + name: "LoomCoinReceived", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "validator", + type: "address" + } + ], + name: "AddedValidator", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "validator", + type: "address" + } + ], + name: "RemovedValidator", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "previousOwner", + type: "address" + } + ], + name: "OwnershipRenounced", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "previousOwner", + type: "address" + }, + { + indexed: true, + name: "newOwner", + type: "address" + } + ], + name: "OwnershipTransferred", + type: "event" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "sig", + type: "bytes" + }, + { + name: "contractAddress", + type: "address" + } + ], + name: "withdrawERC20", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + } + ], + name: "depositERC20", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "contractAddress", + type: "address" + } + ], + name: "getERC20", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_allow", + type: "bool" + } + ], + name: "toggleAllowAnyToken", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + } +]; diff --git a/src/mainnet-contracts/ERC20Gateway_v2.d.ts b/src/mainnet-contracts/ERC20Gateway_v2.d.ts new file mode 100644 index 00000000..a699c5da --- /dev/null +++ b/src/mainnet-contracts/ERC20Gateway_v2.d.ts @@ -0,0 +1,132 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, ContractTransaction, EventFilter, Signer } from "ethers"; +import { Listener, Provider } from "ethers/providers"; +import { Arrayish, BigNumber, BigNumberish, Interface } from "ethers/utils"; +import { + TransactionOverrides, + TypedEventDescription, + TypedFunctionDescription +} from "."; + +interface ERC20Gateway_v2Interface extends Interface { + functions: { + withdrawERC20: TypedFunctionDescription<{ + encode([amount, contractAddress, _signersIndexes, _v, _r, _s]: [ + BigNumberish, + string, + (BigNumberish)[], + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + depositERC20: TypedFunctionDescription<{ + encode([amount, contractAddress]: [BigNumberish, string]): string; + }>; + }; + + events: { + TokenWithdrawn: TypedEventDescription<{ + encodeTopics([owner, kind, contractAddress, value]: [ + string | null, + null, + null, + null + ]): string[]; + }>; + + LoomCoinReceived: TypedEventDescription<{ + encodeTopics([from, amount, loomCoinAddress]: [ + string | null, + null, + null + ]): string[]; + }>; + + ERC20Received: TypedEventDescription<{ + encodeTopics([from, amount, contractAddress]: [ + null, + null, + null + ]): string[]; + }>; + }; +} + +export class ERC20Gateway_v2 extends Contract { + connect(signerOrProvider: Signer | Provider | string): ERC20Gateway_v2; + attach(addressOrName: string): ERC20Gateway_v2; + deployed(): Promise; + + on(event: EventFilter | string, listener: Listener): ERC20Gateway_v2; + once(event: EventFilter | string, listener: Listener): ERC20Gateway_v2; + addListener( + eventName: EventFilter | string, + listener: Listener + ): ERC20Gateway_v2; + removeAllListeners(eventName: EventFilter | string): ERC20Gateway_v2; + removeListener(eventName: any, listener: Listener): ERC20Gateway_v2; + + interface: ERC20Gateway_v2Interface; + + functions: { + nonces(arg0: string): Promise; + + getERC20(contractAddress: string): Promise; + + withdrawERC20( + amount: BigNumberish, + contractAddress: string, + _signersIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + depositERC20( + amount: BigNumberish, + contractAddress: string, + overrides?: TransactionOverrides + ): Promise; + + vmc(): Promise; + loomAddress(): Promise; + }; + + filters: { + TokenWithdrawn( + owner: string | null, + kind: null, + contractAddress: null, + value: null + ): EventFilter; + + LoomCoinReceived( + from: string | null, + amount: null, + loomCoinAddress: null + ): EventFilter; + + ERC20Received(from: null, amount: null, contractAddress: null): EventFilter; + }; + + estimate: { + withdrawERC20( + amount: BigNumberish, + contractAddress: string, + _signersIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + depositERC20( + amount: BigNumberish, + contractAddress: string + ): Promise; + }; +} diff --git a/src/mainnet-contracts/ERC20Gateway_v2Factory.ts b/src/mainnet-contracts/ERC20Gateway_v2Factory.ts new file mode 100644 index 00000000..b1c16b81 --- /dev/null +++ b/src/mainnet-contracts/ERC20Gateway_v2Factory.ts @@ -0,0 +1,219 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, Signer } from "ethers"; +import { Provider } from "ethers/providers"; + +import { ERC20Gateway_v2 } from "./ERC20Gateway_v2"; + +export class ERC20Gateway_v2Factory { + static connect( + address: string, + signerOrProvider: Signer | Provider + ): ERC20Gateway_v2 { + return new Contract(address, _abi, signerOrProvider) as ERC20Gateway_v2; + } +} + +const _abi = [ + { + constant: true, + inputs: [], + name: "vmc", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [], + name: "loomAddress", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "address" + } + ], + name: "nonces", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + inputs: [ + { + name: "_vmc", + type: "address" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "constructor" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "owner", + type: "address" + }, + { + indexed: false, + name: "kind", + type: "uint8" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + }, + { + indexed: false, + name: "value", + type: "uint256" + } + ], + name: "TokenWithdrawn", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "loomCoinAddress", + type: "address" + } + ], + name: "LoomCoinReceived", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + } + ], + name: "ERC20Received", + type: "event" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + }, + { + name: "_signersIndexes", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "withdrawERC20", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + } + ], + name: "depositERC20", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "contractAddress", + type: "address" + } + ], + name: "getERC20", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + } +]; diff --git a/src/mainnet-contracts/Gateway.d.ts b/src/mainnet-contracts/Gateway.d.ts new file mode 100644 index 00000000..e3e1ca5a --- /dev/null +++ b/src/mainnet-contracts/Gateway.d.ts @@ -0,0 +1,368 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, ContractTransaction, EventFilter, Signer } from "ethers"; +import { Listener, Provider } from "ethers/providers"; +import { Arrayish, BigNumber, BigNumberish, Interface } from "ethers/utils"; +import { + TransactionOverrides, + TypedEventDescription, + TypedFunctionDescription +} from "."; + +interface GatewayInterface extends Interface { + functions: { + depositERC20: TypedFunctionDescription<{ + encode([amount, contractAddress]: [BigNumberish, string]): string; + }>; + + withdrawERC20: TypedFunctionDescription<{ + encode([amount, contractAddress, _valIndexes, _v, _r, _s]: [ + BigNumberish, + string, + (BigNumberish)[], + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + withdrawERC721X: TypedFunctionDescription<{ + encode([tokenId, amount, contractAddress, _valIndexes, _v, _r, _s]: [ + BigNumberish, + BigNumberish, + string, + (BigNumberish)[], + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + withdrawERC721: TypedFunctionDescription<{ + encode([uid, contractAddress, _valIndexes, _v, _r, _s]: [ + BigNumberish, + string, + (BigNumberish)[], + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + withdrawETH: TypedFunctionDescription<{ + encode([amount, _valIndexes, _v, _r, _s]: [ + BigNumberish, + (BigNumberish)[], + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + onERC721XReceived: TypedFunctionDescription<{ + encode([_operator, _from, _tokenId, _amount, _data]: [ + string, + string, + BigNumberish, + BigNumberish, + Arrayish + ]): string; + }>; + + onERC721XBatchReceived: TypedFunctionDescription<{ + encode([_operator, _from, _types, _amounts, _data]: [ + string, + string, + (BigNumberish)[], + (BigNumberish)[], + Arrayish + ]): string; + }>; + + onERC721Received: TypedFunctionDescription<{ + encode([_operator, _from, _uid, _data]: [ + string, + string, + BigNumberish, + Arrayish + ]): string; + }>; + }; + + events: { + ETHReceived: TypedEventDescription<{ + encodeTopics([from, amount]: [null, null]): string[]; + }>; + + ERC721Received: TypedEventDescription<{ + encodeTopics([operator, from, tokenId, contractAddress, data]: [ + null, + null, + null, + null, + null + ]): string[]; + }>; + + ERC721XReceived: TypedEventDescription<{ + encodeTopics([operator, from, tokenId, amount, contractAddress, data]: [ + null, + null, + null, + null, + null, + null + ]): string[]; + }>; + + ERC721XBatchReceived: TypedEventDescription<{ + encodeTopics([operator, to, tokenTypes, amounts, contractAddress, data]: [ + null, + null, + null, + null, + null, + null + ]): string[]; + }>; + + ERC20Received: TypedEventDescription<{ + encodeTopics([from, amount, contractAddress]: [ + null, + null, + null + ]): string[]; + }>; + + TokenWithdrawn: TypedEventDescription<{ + encodeTopics([owner, kind, contractAddress, value]: [ + string | null, + null, + null, + null + ]): string[]; + }>; + + LoomCoinReceived: TypedEventDescription<{ + encodeTopics([from, amount, loomCoinAddress]: [ + string | null, + null, + null + ]): string[]; + }>; + }; +} + +export class Gateway extends Contract { + connect(signerOrProvider: Signer | Provider | string): Gateway; + attach(addressOrName: string): Gateway; + deployed(): Promise; + + on(event: EventFilter | string, listener: Listener): Gateway; + once(event: EventFilter | string, listener: Listener): Gateway; + addListener(eventName: EventFilter | string, listener: Listener): Gateway; + removeAllListeners(eventName: EventFilter | string): Gateway; + removeListener(eventName: any, listener: Listener): Gateway; + + interface: GatewayInterface; + + functions: { + getERC20(contractAddress: string): Promise; + + nonces(arg0: string): Promise; + + getERC721(uid: BigNumberish, contractAddress: string): Promise; + + getERC721X( + tokenId: BigNumberish, + contractAddress: string + ): Promise; + + depositERC20( + amount: BigNumberish, + contractAddress: string, + overrides?: TransactionOverrides + ): Promise; + + withdrawERC20( + amount: BigNumberish, + contractAddress: string, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + withdrawERC721X( + tokenId: BigNumberish, + amount: BigNumberish, + contractAddress: string, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + withdrawERC721( + uid: BigNumberish, + contractAddress: string, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + withdrawETH( + amount: BigNumberish, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + onERC721XReceived( + _operator: string, + _from: string, + _tokenId: BigNumberish, + _amount: BigNumberish, + _data: Arrayish, + overrides?: TransactionOverrides + ): Promise; + + onERC721XBatchReceived( + _operator: string, + _from: string, + _types: (BigNumberish)[], + _amounts: (BigNumberish)[], + _data: Arrayish, + overrides?: TransactionOverrides + ): Promise; + + onERC721Received( + _operator: string, + _from: string, + _uid: BigNumberish, + _data: Arrayish, + overrides?: TransactionOverrides + ): Promise; + + loomAddress(): Promise; + getETH(): Promise; + }; + + filters: { + ETHReceived(from: null, amount: null): EventFilter; + + ERC721Received( + operator: null, + from: null, + tokenId: null, + contractAddress: null, + data: null + ): EventFilter; + + ERC721XReceived( + operator: null, + from: null, + tokenId: null, + amount: null, + contractAddress: null, + data: null + ): EventFilter; + + ERC721XBatchReceived( + operator: null, + to: null, + tokenTypes: null, + amounts: null, + contractAddress: null, + data: null + ): EventFilter; + + ERC20Received(from: null, amount: null, contractAddress: null): EventFilter; + + TokenWithdrawn( + owner: string | null, + kind: null, + contractAddress: null, + value: null + ): EventFilter; + + LoomCoinReceived( + from: string | null, + amount: null, + loomCoinAddress: null + ): EventFilter; + }; + + estimate: { + depositERC20( + amount: BigNumberish, + contractAddress: string + ): Promise; + + withdrawERC20( + amount: BigNumberish, + contractAddress: string, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + withdrawERC721X( + tokenId: BigNumberish, + amount: BigNumberish, + contractAddress: string, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + withdrawERC721( + uid: BigNumberish, + contractAddress: string, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + withdrawETH( + amount: BigNumberish, + _valIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + onERC721XReceived( + _operator: string, + _from: string, + _tokenId: BigNumberish, + _amount: BigNumberish, + _data: Arrayish + ): Promise; + + onERC721XBatchReceived( + _operator: string, + _from: string, + _types: (BigNumberish)[], + _amounts: (BigNumberish)[], + _data: Arrayish + ): Promise; + + onERC721Received( + _operator: string, + _from: string, + _uid: BigNumberish, + _data: Arrayish + ): Promise; + }; +} diff --git a/src/mainnet-contracts/GatewayFactory.ts b/src/mainnet-contracts/GatewayFactory.ts new file mode 100644 index 00000000..f85d231f --- /dev/null +++ b/src/mainnet-contracts/GatewayFactory.ts @@ -0,0 +1,596 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, Signer } from "ethers"; +import { Provider } from "ethers/providers"; + +import { Gateway } from "./Gateway"; + +export class GatewayFactory { + static connect( + address: string, + signerOrProvider: Signer | Provider + ): Gateway { + return new Contract(address, _abi, signerOrProvider) as Gateway; + } +} + +const _abi = [ + { + constant: true, + inputs: [], + name: "loomAddress", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + } + ], + name: "depositERC20", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "contractAddress", + type: "address" + } + ], + name: "getERC20", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "address" + } + ], + name: "nonces", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + }, + { + name: "_valIndexes", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "withdrawERC20", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + inputs: [ + { + name: "_vmc", + type: "address" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "constructor" + }, + { + payable: true, + stateMutability: "payable", + type: "fallback" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + } + ], + name: "ETHReceived", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "operator", + type: "address" + }, + { + indexed: false, + name: "from", + type: "address" + }, + { + indexed: false, + name: "tokenId", + type: "uint256" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + }, + { + indexed: false, + name: "data", + type: "bytes" + } + ], + name: "ERC721Received", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "operator", + type: "address" + }, + { + indexed: false, + name: "from", + type: "address" + }, + { + indexed: false, + name: "tokenId", + type: "uint256" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + }, + { + indexed: false, + name: "data", + type: "bytes" + } + ], + name: "ERC721XReceived", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "operator", + type: "address" + }, + { + indexed: false, + name: "to", + type: "address" + }, + { + indexed: false, + name: "tokenTypes", + type: "uint256[]" + }, + { + indexed: false, + name: "amounts", + type: "uint256[]" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + }, + { + indexed: false, + name: "data", + type: "bytes" + } + ], + name: "ERC721XBatchReceived", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + } + ], + name: "ERC20Received", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "owner", + type: "address" + }, + { + indexed: false, + name: "kind", + type: "uint8" + }, + { + indexed: false, + name: "contractAddress", + type: "address" + }, + { + indexed: false, + name: "value", + type: "uint256" + } + ], + name: "TokenWithdrawn", + type: "event" + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: "from", + type: "address" + }, + { + indexed: false, + name: "amount", + type: "uint256" + }, + { + indexed: false, + name: "loomCoinAddress", + type: "address" + } + ], + name: "LoomCoinReceived", + type: "event" + }, + { + constant: false, + inputs: [ + { + name: "tokenId", + type: "uint256" + }, + { + name: "amount", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + }, + { + name: "_valIndexes", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "withdrawERC721X", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "uid", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + }, + { + name: "_valIndexes", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "withdrawERC721", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "amount", + type: "uint256" + }, + { + name: "_valIndexes", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "withdrawETH", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_operator", + type: "address" + }, + { + name: "_from", + type: "address" + }, + { + name: "_tokenId", + type: "uint256" + }, + { + name: "_amount", + type: "uint256" + }, + { + name: "_data", + type: "bytes" + } + ], + name: "onERC721XReceived", + outputs: [ + { + name: "", + type: "bytes4" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_operator", + type: "address" + }, + { + name: "_from", + type: "address" + }, + { + name: "_types", + type: "uint256[]" + }, + { + name: "_amounts", + type: "uint256[]" + }, + { + name: "_data", + type: "bytes" + } + ], + name: "onERC721XBatchReceived", + outputs: [ + { + name: "", + type: "bytes4" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: false, + inputs: [ + { + name: "_operator", + type: "address" + }, + { + name: "_from", + type: "address" + }, + { + name: "_uid", + type: "uint256" + }, + { + name: "_data", + type: "bytes" + } + ], + name: "onERC721Received", + outputs: [ + { + name: "", + type: "bytes4" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "function" + }, + { + constant: true, + inputs: [], + name: "getETH", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "uid", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + } + ], + name: "getERC721", + outputs: [ + { + name: "", + type: "bool" + } + ], + payable: false, + stateMutability: "view", + type: "function" + }, + { + constant: true, + inputs: [ + { + name: "tokenId", + type: "uint256" + }, + { + name: "contractAddress", + type: "address" + } + ], + name: "getERC721X", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function" + } +]; diff --git a/src/mainnet-contracts/ValidatorManagerContract.d.ts b/src/mainnet-contracts/ValidatorManagerContract.d.ts new file mode 100644 index 00000000..559c4eec --- /dev/null +++ b/src/mainnet-contracts/ValidatorManagerContract.d.ts @@ -0,0 +1,151 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, ContractTransaction, EventFilter, Signer } from "ethers"; +import { Listener, Provider } from "ethers/providers"; +import { Arrayish, BigNumber, BigNumberish, Interface } from "ethers/utils"; +import { + TransactionOverrides, + TypedEventDescription, + TypedFunctionDescription +} from "."; + +interface ValidatorManagerContractInterface extends Interface { + functions: { + rotateValidators: TypedFunctionDescription<{ + encode([_newValidators, _newPowers, _signIndexes, _v, _r, _s]: [ + (string)[], + (BigNumberish)[], + (BigNumberish)[], + (BigNumberish)[], + (Arrayish)[], + (Arrayish)[] + ]): string; + }>; + + toggleAllowAnyToken: TypedFunctionDescription<{ + encode([allow, validatorIndex]: [boolean, BigNumberish]): string; + }>; + + toggleAllowToken: TypedFunctionDescription<{ + encode([tokenAddress, allow, validatorIndex]: [ + string, + boolean, + BigNumberish + ]): string; + }>; + }; + + events: { + ValidatorSetChanged: TypedEventDescription<{ + encodeTopics([_validators, _powers]: [null, null]): string[]; + }>; + }; +} + +export class ValidatorManagerContract extends Contract { + connect( + signerOrProvider: Signer | Provider | string + ): ValidatorManagerContract; + attach(addressOrName: string): ValidatorManagerContract; + deployed(): Promise; + + on(event: EventFilter | string, listener: Listener): ValidatorManagerContract; + once( + event: EventFilter | string, + listener: Listener + ): ValidatorManagerContract; + addListener( + eventName: EventFilter | string, + listener: Listener + ): ValidatorManagerContract; + removeAllListeners(eventName: EventFilter | string): ValidatorManagerContract; + removeListener(eventName: any, listener: Listener): ValidatorManagerContract; + + interface: ValidatorManagerContractInterface; + + functions: { + validators(arg0: BigNumberish): Promise; + + powers(arg0: BigNumberish): Promise; + + nonces(arg0: string): Promise; + + allowedTokens(arg0: string): Promise; + + signedByValidator( + _message: Arrayish, + signersIndex: BigNumberish, + _v: BigNumberish, + _r: Arrayish, + _s: Arrayish + ): Promise; + + checkThreshold( + _message: Arrayish, + signersIndex: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + isTokenAllowed(tokenAddress: string): Promise; + + rotateValidators( + _newValidators: (string)[], + _newPowers: (BigNumberish)[], + _signIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[], + overrides?: TransactionOverrides + ): Promise; + + toggleAllowAnyToken( + allow: boolean, + validatorIndex: BigNumberish, + overrides?: TransactionOverrides + ): Promise; + + toggleAllowToken( + tokenAddress: string, + allow: boolean, + validatorIndex: BigNumberish, + overrides?: TransactionOverrides + ): Promise; + + loomAddress(): Promise; + threshold_denom(): Promise; + nonce(): Promise; + threshold_num(): Promise; + totalPower(): Promise; + getPowers(): Promise<(BigNumber)[]>; + getValidators(): Promise<(string)[]>; + }; + + filters: { + ValidatorSetChanged(_validators: null, _powers: null): EventFilter; + }; + + estimate: { + rotateValidators( + _newValidators: (string)[], + _newPowers: (BigNumberish)[], + _signIndexes: (BigNumberish)[], + _v: (BigNumberish)[], + _r: (Arrayish)[], + _s: (Arrayish)[] + ): Promise; + + toggleAllowAnyToken( + allow: boolean, + validatorIndex: BigNumberish + ): Promise; + + toggleAllowToken( + tokenAddress: string, + allow: boolean, + validatorIndex: BigNumberish + ): Promise; + }; +} diff --git a/src/mainnet-contracts/ValidatorManagerContractFactory.ts b/src/mainnet-contracts/ValidatorManagerContractFactory.ts new file mode 100644 index 00000000..e9212e6a --- /dev/null +++ b/src/mainnet-contracts/ValidatorManagerContractFactory.ts @@ -0,0 +1,414 @@ +/* Generated by ts-generator ver. 0.0.8 */ +/* tslint:disable */ + +import { Contract, Signer } from "ethers"; +import { Provider } from "ethers/providers"; + +import { ValidatorManagerContract } from "./ValidatorManagerContract"; + +export class ValidatorManagerContractFactory { + static connect( + address: string, + signerOrProvider: Signer | Provider + ): ValidatorManagerContract { + return new Contract( + address, + _abi, + signerOrProvider + ) as ValidatorManagerContract; + } +} + +const _abi = [ + { + constant: true, + inputs: [ + { + name: "", + type: "uint256" + } + ], + name: "validators", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x35aa2e44" + }, + { + constant: true, + inputs: [], + name: "loomAddress", + outputs: [ + { + name: "", + type: "address" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x37179db8" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "uint256" + } + ], + name: "powers", + outputs: [ + { + name: "", + type: "uint64" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x40c1bfab" + }, + { + constant: true, + inputs: [], + name: "threshold_denom", + outputs: [ + { + name: "", + type: "uint8" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x57d717d1" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "address" + } + ], + name: "nonces", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x7ecebe00" + }, + { + constant: true, + inputs: [], + name: "nonce", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xaffed0e0" + }, + { + constant: true, + inputs: [], + name: "threshold_num", + outputs: [ + { + name: "", + type: "uint8" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xc57829d2" + }, + { + constant: true, + inputs: [], + name: "totalPower", + outputs: [ + { + name: "", + type: "uint256" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xdb3ad22c" + }, + { + constant: true, + inputs: [ + { + name: "", + type: "address" + } + ], + name: "allowedTokens", + outputs: [ + { + name: "", + type: "bool" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xe744092e" + }, + { + inputs: [ + { + name: "_validators", + type: "address[]" + }, + { + name: "_powers", + type: "uint64[]" + }, + { + name: "_threshold_num", + type: "uint8" + }, + { + name: "_threshold_denom", + type: "uint8" + }, + { + name: "_loomAddress", + type: "address" + } + ], + payable: false, + stateMutability: "nonpayable", + type: "constructor", + signature: "constructor" + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + name: "_validators", + type: "address[]" + }, + { + indexed: false, + name: "_powers", + type: "uint64[]" + } + ], + name: "ValidatorSetChanged", + type: "event", + signature: + "0x323c51e0ad42c317ff3b00c6ce354d799a4b5eaf3a25cf3169cf2efd339d4d54" + }, + { + constant: true, + inputs: [], + name: "getPowers", + outputs: [ + { + name: "", + type: "uint64[]" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xff13a1ac" + }, + { + constant: true, + inputs: [], + name: "getValidators", + outputs: [ + { + name: "", + type: "address[]" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xb7ab4db5" + }, + { + constant: false, + inputs: [ + { + name: "_newValidators", + type: "address[]" + }, + { + name: "_newPowers", + type: "uint64[]" + }, + { + name: "_signIndexes", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "rotateValidators", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + signature: "0xeb2eb0ef" + }, + { + constant: true, + inputs: [ + { + name: "_message", + type: "bytes32" + }, + { + name: "signersIndex", + type: "uint256" + }, + { + name: "_v", + type: "uint8" + }, + { + name: "_r", + type: "bytes32" + }, + { + name: "_s", + type: "bytes32" + } + ], + name: "signedByValidator", + outputs: [], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xc47c479a" + }, + { + constant: true, + inputs: [ + { + name: "_message", + type: "bytes32" + }, + { + name: "signersIndex", + type: "uint256[]" + }, + { + name: "_v", + type: "uint8[]" + }, + { + name: "_r", + type: "bytes32[]" + }, + { + name: "_s", + type: "bytes32[]" + } + ], + name: "checkThreshold", + outputs: [], + payable: false, + stateMutability: "view", + type: "function", + signature: "0x0fba29c3" + }, + { + constant: true, + inputs: [ + { + name: "tokenAddress", + type: "address" + } + ], + name: "isTokenAllowed", + outputs: [ + { + name: "", + type: "bool" + } + ], + payable: false, + stateMutability: "view", + type: "function", + signature: "0xf9eaee0d" + }, + { + constant: false, + inputs: [ + { + name: "allow", + type: "bool" + }, + { + name: "validatorIndex", + type: "uint256" + } + ], + name: "toggleAllowAnyToken", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + signature: "0x1a6be287" + }, + { + constant: false, + inputs: [ + { + name: "tokenAddress", + type: "address" + }, + { + name: "allow", + type: "bool" + }, + { + name: "validatorIndex", + type: "uint256" + } + ], + name: "toggleAllowToken", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + signature: "0xe3ece440" + } +]; diff --git a/src/tests/e2e/address-mapper-tests.ts b/src/tests/e2e/contracts/address-mapper-tests.ts similarity index 90% rename from src/tests/e2e/address-mapper-tests.ts rename to src/tests/e2e/contracts/address-mapper-tests.ts index 90585282..f1d4673f 100644 --- a/src/tests/e2e/address-mapper-tests.ts +++ b/src/tests/e2e/contracts/address-mapper-tests.ts @@ -7,10 +7,9 @@ import { CryptoUtils, createDefaultTxMiddleware, Contracts -} from '../../index' -import { createTestHttpClient } from '../helpers' -import { EthersSigner, getJsonRPCSignerAsync } from '../../solidity-helpers' -import { ethers, Signer } from 'ethers' +} from '../../../index' +import { createTestHttpClient } from '../../helpers' +import { EthersSigner, getJsonRPCSignerAsync } from '../../../solidity-helpers' async function getClientAndContract( createClient: () => Client diff --git a/src/tests/e2e/coin-tests.ts b/src/tests/e2e/contracts/coin-tests.ts similarity index 97% rename from src/tests/e2e/coin-tests.ts rename to src/tests/e2e/contracts/coin-tests.ts index bc90d96b..a9933520 100644 --- a/src/tests/e2e/coin-tests.ts +++ b/src/tests/e2e/contracts/coin-tests.ts @@ -7,9 +7,9 @@ import { createDefaultTxMiddleware, Client, LocalAddress -} from '../../index' -import { createTestHttpClient } from '../helpers' -import { B64ToUint8Array } from '../../crypto-utils' +} from '../../../index' +import { createTestHttpClient } from '../../helpers' +import { B64ToUint8Array } from '../../../crypto-utils' const toCoinE18 = (amount: number): BN => { return new BN(10).pow(new BN(18)).mul(new BN(amount)) diff --git a/src/tests/e2e/contract-tests.ts b/src/tests/e2e/contracts/contract-tests.ts similarity index 97% rename from src/tests/e2e/contract-tests.ts rename to src/tests/e2e/contracts/contract-tests.ts index 40b6608f..e6740ba8 100644 --- a/src/tests/e2e/contract-tests.ts +++ b/src/tests/e2e/contracts/contract-tests.ts @@ -8,14 +8,14 @@ import { IChainEventArgs, CryptoUtils, createDefaultTxMiddleware -} from '../../index' -import { MapEntry } from '../tests_pb' +} from '../../../index' +import { MapEntry } from '../../tests_pb' import { createTestClient, createTestHttpClient, createTestWSClient, createTestHttpWSClient -} from '../helpers' +} from '../../helpers' async function getClientAndContract( createClient: () => Client diff --git a/src/tests/e2e/dpos-tests.ts b/src/tests/e2e/contracts/dpos-tests.ts similarity index 96% rename from src/tests/e2e/dpos-tests.ts rename to src/tests/e2e/contracts/dpos-tests.ts index 9c8998fd..63d0a62c 100644 --- a/src/tests/e2e/dpos-tests.ts +++ b/src/tests/e2e/contracts/dpos-tests.ts @@ -1,5 +1,4 @@ import test from 'tape' -import BN from 'bn.js' import { Address, Contracts, @@ -7,9 +6,9 @@ import { createDefaultTxMiddleware, Client, LocalAddress -} from '../../index' -import { createTestHttpClient, waitForMillisecondsAsync } from '../helpers' -import { B64ToUint8Array } from '../../crypto-utils' +} from '../../../index' +import { createTestHttpClient, waitForMillisecondsAsync } from '../../helpers' +import { B64ToUint8Array } from '../../../crypto-utils' async function getClientAndContract( createClient: () => Client diff --git a/src/tests/e2e/client-evm-event-tests-2.ts b/src/tests/e2e/evm/client-evm-event-tests-2.ts similarity index 83% rename from src/tests/e2e/client-evm-event-tests-2.ts rename to src/tests/e2e/evm/client-evm-event-tests-2.ts index 0a4359f7..5101bb92 100644 --- a/src/tests/e2e/client-evm-event-tests-2.ts +++ b/src/tests/e2e/evm/client-evm-event-tests-2.ts @@ -1,13 +1,13 @@ import test from 'tape' -import { CryptoUtils, Client } from '../../index' -import { createTestClient, waitForMillisecondsAsync } from '../helpers' -import { CallTx, VMType, MessageTx, Transaction } from '../../proto/loom_pb' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { bufferToProtobufBytes } from '../../crypto-utils' -import { Address, LocalAddress } from '../../address' -import { createDefaultTxMiddleware } from '../../helpers' +import { CryptoUtils, Client } from '../../../index' +import { createTestClient, waitForMillisecondsAsync } from '../../helpers' +import { CallTx, VMType, MessageTx, Transaction } from '../../../proto/loom_pb' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { bufferToProtobufBytes } from '../../../crypto-utils' +import { Address, LocalAddress } from '../../../address' +import { createDefaultTxMiddleware } from '../../../helpers' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -100,11 +100,8 @@ test('Client EVM Event test (two filters)', async t => { address: result.contractAddress } - const filterCreated1 = await client.evmSubscribeAsync('logs', filter1) - const filterCreated2 = await client.evmSubscribeAsync('logs', filter2) - - console.log('Filter 1 created', filterCreated1) - console.log('Filter 2 created', filterCreated2) + await client.evmSubscribeAsync('logs', filter1) + await client.evmSubscribeAsync('logs', filter2) const caller = new Address('default', LocalAddress.fromPublicKey(publicKey)) const address = new Address('default', LocalAddress.fromHexString(result.contractAddress)) @@ -124,7 +121,6 @@ test('Client EVM Event test (two filters)', async t => { waitForMillisecondsAsync(2000) } catch (err) { - console.error(err) t.fail(err.message) } diff --git a/src/tests/e2e/client-evm-event-tests.ts b/src/tests/e2e/evm/client-evm-event-tests.ts similarity index 88% rename from src/tests/e2e/client-evm-event-tests.ts rename to src/tests/e2e/evm/client-evm-event-tests.ts index 891f388f..a387aa02 100644 --- a/src/tests/e2e/client-evm-event-tests.ts +++ b/src/tests/e2e/evm/client-evm-event-tests.ts @@ -1,12 +1,12 @@ import test from 'tape' -import { NonceTxMiddleware, SignedTxMiddleware, CryptoUtils } from '../../index' -import { createTestClient } from '../helpers' -import { CallTx, VMType, MessageTx, Transaction } from '../../proto/loom_pb' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { bufferToProtobufBytes } from '../../crypto-utils' -import { Address, LocalAddress } from '../../address' +import { NonceTxMiddleware, SignedTxMiddleware, CryptoUtils } from '../../../index' +import { createTestClient } from '../../helpers' +import { CallTx, VMType, MessageTx, Transaction } from '../../../proto/loom_pb' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { bufferToProtobufBytes } from '../../../crypto-utils' +import { Address, LocalAddress } from '../../../address' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -78,8 +78,6 @@ test('Client EVM Event test', async t => { const filterCreated = await client.evmSubscribeAsync('logs', filter) - console.log('Filter created', filterCreated) - const caller = new Address('default', LocalAddress.fromPublicKey(publicKey)) const address = new Address('default', LocalAddress.fromHexString(result.contractAddress)) const data = Buffer.from( @@ -101,10 +99,7 @@ test('Client EVM Event test', async t => { tx.setData(msgTx.serializeBinary()) await client.commitTxAsync(tx) - - console.log('Disconnected') } catch (err) { - console.error(err) t.fail(err.message) } diff --git a/src/tests/e2e/client-evm-tests.ts b/src/tests/e2e/evm/client-evm-tests.ts similarity index 86% rename from src/tests/e2e/client-evm-tests.ts rename to src/tests/e2e/evm/client-evm-tests.ts index 8ae98fa5..eb18d9cf 100644 --- a/src/tests/e2e/client-evm-tests.ts +++ b/src/tests/e2e/evm/client-evm-tests.ts @@ -1,10 +1,10 @@ import test from 'tape' -import { CryptoUtils } from '../../index' -import { execAndWaitForMillisecondsAsync, createTestClient } from '../helpers' -import { EthBlockHashList, EthBlockInfo } from '../../proto/evm_pb' -import { bytesToHexAddr } from '../../crypto-utils' -import { createDefaultTxMiddleware } from '../../helpers' +import { CryptoUtils } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync } from '../../helpers' +import { EthBlockHashList, EthBlockInfo } from '../../../proto/evm_pb' +import { bytesToHexAddr } from '../../../crypto-utils' +import { createDefaultTxMiddleware } from '../../../helpers' test('Client EVM test (newBlockEvmFilterAsync)', async t => { let client diff --git a/src/tests/e2e/evm-contract-tests.ts b/src/tests/e2e/evm/evm-contract-tests.ts similarity index 97% rename from src/tests/e2e/evm-contract-tests.ts rename to src/tests/e2e/evm/evm-contract-tests.ts index 16b72dc9..08e931b7 100644 --- a/src/tests/e2e/evm-contract-tests.ts +++ b/src/tests/e2e/evm/evm-contract-tests.ts @@ -6,8 +6,8 @@ import { LocalAddress, CryptoUtils, createDefaultTxMiddleware -} from '../../index' -import { createTestWSClient } from '../helpers' +} from '../../../index' +import { createTestWSClient } from '../../helpers' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -134,7 +134,7 @@ test('EVM Contract Calls', async t => { client.disconnect() } catch (err) { - console.log(err) + t.fail(err) } t.end() }) diff --git a/src/tests/e2e/loom-provider-2/loom-provider-eth-filters.ts b/src/tests/e2e/loom-provider-2/loom-provider-eth-filters.ts new file mode 100644 index 00000000..54dc3a41 --- /dev/null +++ b/src/tests/e2e/loom-provider-2/loom-provider-eth-filters.ts @@ -0,0 +1,178 @@ +import test from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync, getTestUrls } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' + +/** + * Requires the SimpleStore solidity contract deployed on a loomchain. + * go-loom/examples/plugins/evmexample/contract/SimpleStore.sol + * + * pragma solidity ^0.4.22; + * + * contract SimpleStore { + * uint value; + * + * constructor() { + * value = 10; + * } + * + * event NewValueSet(uint _value); + * + * function set(uint _value) public { + * value = _value; + * emit NewValueSet(value); + * } + * + * function get() public view returns (uint) { + * return value; + * } + * } + * + */ + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + const loomProviderLegacy = new LoomProvider(client, privKey) + + const contractData = + '0x608060405234801561001057600080fd5b50600a600081905550610114806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606c575b600080fd5b606a600480360381019080803590602001909291905050506094565b005b348015607757600080fd5b50607e60df565b6040518082815260200191505060405180910390f35b806000819055507f2afa03c814297ffc234ff967b6f0863d3c358be243103f20217c8d3a4d39f9c060005434604051808381526020018281526020019250505060405180910390a150565b600080549050905600a165627a7a72305820deed812a797567167162d0af3ae5f0528c39bea0620e32b28e243628cd655dc40029' + + await deployContract(loomProviderLegacy, contractData) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + + return { + loomProvider + } +} + +test('LoomProvider2 + Filters (1)', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + // Transaction receipt in order to obtain the topic of the event NewValueSet + const ethNewFilterResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 10, + method: 'eth_newFilter', + params: [{ toBlock: 'latest' }] + }) + ) + + t.assert(/0x.+/.test(ethNewFilterResult.result), 'New id should be created for new filter') + + const ethNewBlockFilter = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 11, + method: 'eth_newBlockFilter' + }) + ) + + t.assert( + /0x.+/.test(ethNewBlockFilter.result), + 'New id should be created for new block filter' + ) + + const ethGetFilterChanges = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 12, + method: 'eth_getFilterChanges', + params: [ethNewBlockFilter.result] + }) + ) + + t.assert( + ethGetFilterChanges.result.length > 0, + 'Get filter changes should return array with new blocks' + ) + + const ethUninstallFilterResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 13, + method: 'eth_uninstallFilter', + params: [ethNewBlockFilter.result] + }) + ) + + t.deepEqual(ethUninstallFilterResult.result, true, 'Should uninstall filter and return true') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Filters (2)', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const ethNewBlockFilter = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 11, + method: 'eth_newBlockFilter' + }) + ) + + t.assert( + /0x.+/.test(ethNewBlockFilter.result), + 'New id should be created for new block filter' + ) + + const ethGetFilterChanges = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 12, + method: 'eth_getFilterChanges', + params: [ethNewBlockFilter.result] + }) + ) + + t.assert(ethGetFilterChanges.result.length > 0, 'Should return filter changes') + + const ethGetBlockByHash = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 13, + method: 'eth_getBlockByHash', + params: [ethGetFilterChanges.result[0], true] + }) + ) + + t.assert(ethGetBlockByHash.result, 'Should return the block requested by hash') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) diff --git a/src/tests/e2e/loom-provider-2/loom-provider-eth-get-logs.ts b/src/tests/e2e/loom-provider-2/loom-provider-eth-get-logs.ts new file mode 100644 index 00000000..54509317 --- /dev/null +++ b/src/tests/e2e/loom-provider-2/loom-provider-eth-get-logs.ts @@ -0,0 +1,240 @@ +import test from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { + createTestClient, + execAndWaitForMillisecondsAsync, + getTestUrls, + waitForMillisecondsAsync +} from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' + +/** + * Requires the SimpleStore solidity contract deployed on a loomchain. + * go-loom/examples/plugins/evmexample/contract/SimpleStore.sol + * + * pragma solidity ^0.4.22; + * + * contract SimpleStore { + * uint value; + * + * constructor() { + * value = 10; + * } + * + * event NewValueSet(uint _value); + * + * function set(uint _value) public { + * value = _value; + * emit NewValueSet(value); + * } + * + * function get() public view returns (uint) { + * return value; + * } + * } + * + */ + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + const loomProviderLegacy = new LoomProvider(client, privKey) + + const contractData = + '0x608060405234801561001057600080fd5b50600a600081905550610114806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606c575b600080fd5b606a600480360381019080803590602001909291905050506094565b005b348015607757600080fd5b50607e60df565b6040518082815260200191505060405180910390f35b806000819055507f2afa03c814297ffc234ff967b6f0863d3c358be243103f20217c8d3a4d39f9c060005434604051808381526020018281526020019250505060405180910390a150565b600080549050905600a165627a7a72305820deed812a797567167162d0af3ae5f0528c39bea0620e32b28e243628cd655dc40029' + + const { contractAddress, transactionHash } = await deployContract( + loomProviderLegacy, + contractData + ) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + const from = await loomProvider.wallet.getAddress() + + return { + from, + contractAddress, + loomProvider + } +} + +async function newTransactionToSetState( + loomProvider: LoomProvider2, + contractAddress: string, + fromAddr: string +) { + // Send transaction to function set in order dispatch event NewValueSet + const ethSendTransactionResult = await loomProvider.sendAsync({ + id: 1, + method: 'eth_sendTransaction', + params: [ + { + to: contractAddress, + from: fromAddr, + data: '0x60fe47b10000000000000000000000000000000000000000000000000000000000000002', + gas: '0x0', + gasPrice: '0x0', + value: '0x0' + } + ] + }) + + await waitForMillisecondsAsync(2000) + + // Transaction receipt in order to obtain the topic of the event NewValueSet + const ethGetTransactionReceiptResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 2, + method: 'eth_getTransactionReceipt', + params: [ethSendTransactionResult.result] + }) + ) + + return { ethGetTransactionReceiptResult, contractAddress } +} + +async function testGetLogsPendingState( + t: test.Test, + loomProvider: LoomProvider2, + contractAddress: string, + fromAddr: string +) { + const newSetTransaction = await newTransactionToSetState(loomProvider, contractAddress, fromAddr) + + // Filtering to get logs + let ethGetLogs = await loomProvider.sendAsync({ + id: 3, + method: 'eth_getLogs', + params: [ + { + address: newSetTransaction.contractAddress, + fromBlock: '0x1', + toBlock: 'pending', + topics: [newSetTransaction.ethGetTransactionReceiptResult.result.logs[0].topics[0]] + } + ] + }) + + t.equal(ethGetLogs.result.length, 1, 'Should return one log for the pending block') +} + +async function testGetLogsLatest( + t: test.Test, + loomProvider: LoomProvider2, + contractAddress: string, + fromAddr: string +) { + const newSetTransaction = await newTransactionToSetState(loomProvider, contractAddress, fromAddr) + + // Filtering to get logs + let ethGetLogs = await loomProvider.sendAsync({ + id: 4, + method: 'eth_getLogs', + params: [ + { + address: newSetTransaction.contractAddress, + fromBlock: '0x1', + toBlock: 'latest', + topics: [newSetTransaction.ethGetTransactionReceiptResult.result.logs[0].topics[0]] + } + ] + }) + + t.equal(ethGetLogs.result.length, 1, 'Should return one log for the latest block') +} + +async function testGetLogsAny( + t: test.Test, + loomProvider: LoomProvider2, + contractAddress: string, + fromAddr: string +) { + const curBlock = await loomProvider.sendAsync({ + id: 6, + method: 'eth_blockNumber', + params: [] + }) + + const fromBlock = curBlock.result + await newTransactionToSetState(loomProvider, contractAddress, fromAddr) + + // Filtering to get logs + let ethGetLogs = await loomProvider.sendAsync({ + id: 7, + method: 'eth_getLogs', + params: [{ fromBlock }] + }) + + t.equal(ethGetLogs.result.length, 1, ' LoomProvider.getEVMLogsAsync one log for anything filter') +} + +async function testGetLogsAnyPending( + t: test.Test, + loomProvider: LoomProvider2, + contractAddress: string, + fromAddr: string +) { + const curBlock = await loomProvider.sendAsync({ + id: 8, + method: 'eth_blockNumber', + params: [] + }) + const fromBlock = curBlock.result + await newTransactionToSetState(loomProvider, contractAddress, fromAddr) + + // Filtering to get logs + let ethGetLogs = await loomProvider.sendAsync({ + id: 9, + method: 'eth_getLogs', + params: [{ fromBlock, toBlock: 'pending' }] + }) + + t.equal(ethGetLogs.result.length, 1, 'Should return one log for anything pending filter') +} + +test('LoomProvider2.getEVMLogsAsync', async t => { + const { loomProvider, from, contractAddress } = await bootstrapLoomProviderTest() + + try { + await testGetLogsPendingState(t, loomProvider, contractAddress, from) + // TODO: Check why is returning two results instead of only one + // await testGetLogsLatest(t, loomProvider, contractAddress, from) + await testGetLogsAny(t, loomProvider, contractAddress, from) + await testGetLogsAnyPending(t, loomProvider, contractAddress, from) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) diff --git a/src/tests/e2e/loom-provider-2/loom-provider-subscribe.ts b/src/tests/e2e/loom-provider-2/loom-provider-subscribe.ts new file mode 100644 index 00000000..84787ad6 --- /dev/null +++ b/src/tests/e2e/loom-provider-2/loom-provider-subscribe.ts @@ -0,0 +1,148 @@ +import test from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync, getTestUrls } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' + +/** + * Requires the SimpleStore solidity contract deployed on a loomchain. + * go-loom/examples/plugins/evmexample/contract/SimpleStore.sol + * + * pragma solidity ^0.4.22; + * + * contract SimpleStore { + * uint value; + * + * constructor() { + * value = 10; + * } + * + * event NewValueSet(uint _value); + * + * function set(uint _value) public { + * value = _value; + * emit NewValueSet(value); + * } + * + * function get() public view returns (uint) { + * return value; + * } + * } + * + */ + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + const loomProviderLegacy = new LoomProvider(client, privKey) + + const contractData = + '0x608060405234801561001057600080fd5b50600a600081905550610114806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606c575b600080fd5b606a600480360381019080803590602001909291905050506094565b005b348015607757600080fd5b50607e60df565b6040518082815260200191505060405180910390f35b806000819055507f2afa03c814297ffc234ff967b6f0863d3c358be243103f20217c8d3a4d39f9c060005434604051808381526020018281526020019250505060405180910390a150565b600080549050905600a165627a7a72305820deed812a797567167162d0af3ae5f0528c39bea0620e32b28e243628cd655dc40029' + + const { contractAddress, transactionHash } = await deployContract( + loomProviderLegacy, + contractData + ) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + const from = await loomProvider.wallet.getAddress() + + return { + from, + contractAddress, + transactionHash, + loomProvider + } +} + +test('LoomProvider2 + Subscribe', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethSubscribeNewHardsResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_subscribe', + params: ['newHeads', {}] + }) + ) + + t.equal(ethSubscribeNewHardsResult.id, id, `Id for eth_subscribe should be equal ${id}`) + t.assert( + /0x.+/.test(ethSubscribeNewHardsResult.result), + 'Filter identification should be returned on eth_subscribe' + ) + + const ethUnsubscribeNewHeadsResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_unsubscribe', + params: [ethSubscribeNewHardsResult.result] + }) + ) + + t.equal(ethUnsubscribeNewHeadsResult.id, id, `Id for eth_unsubscribe should be equal ${id}`) + t.assert(ethUnsubscribeNewHeadsResult.result, 'Unsubscribed for newHeads') + + const ethSubscribeLogsResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_subscribe', + params: ['logs', {}] + }) + ) + + t.equal(ethSubscribeLogsResult.id, id, `Id for eth_subscribe should be equal ${id}`) + t.assert( + /0x.+/.test(ethSubscribeLogsResult.result), + 'Filter identification should be returned on eth_subscribe' + ) + + const ethUnsubscribeLogsResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_unsubscribe', + params: [ethSubscribeLogsResult.result] + }) + ) + + t.equal(ethUnsubscribeLogsResult.id, id, `Id for eth_unsubscribe should be equal ${id}`) + t.assert(ethUnsubscribeLogsResult.result, 'Unsubscribed for Logs') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) diff --git a/src/tests/e2e/loom-provider-2/loom-provider-tests.ts b/src/tests/e2e/loom-provider-2/loom-provider-tests.ts new file mode 100644 index 00000000..49402109 --- /dev/null +++ b/src/tests/e2e/loom-provider-2/loom-provider-tests.ts @@ -0,0 +1,444 @@ +import test from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync, getTestUrls } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' + +/** + * Requires the SimpleStore solidity contract deployed on a loomchain. + * go-loom/examples/plugins/evmexample/contract/SimpleStore.sol + * + * pragma solidity ^0.4.18; + * contract SimpleStore { + * function set(uint _value) public { + * value = _value; + * } + * function get() public constant returns (uint) { + * return value; + * } + * uint value; + * } + * + */ + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + const loomProviderLegacy = new LoomProvider(client, privKey) + + const contractData = + '608060405234801561001057600080fd5b50600a600081905550610118806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60e3565b6040518082815260200191505060405180910390f35b806000819055507fb922f092a64f1a076de6f21e4d7c6400b6e55791cc935e7bb8e7e90f7652f15b6000546040518082815260200191505060405180910390a150565b600080549050905600a165627a7a72305820fabe42649c29e53c4b9fad19100d72a1e825603058e1678432a76f94a10d352a0029' + + const { contractAddress, transactionHash } = await deployContract( + loomProviderLegacy, + contractData + ) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + const from = await loomProvider.wallet.getAddress() + + return { + from, + contractAddress, + transactionHash, + loomProvider + } +} + +test('LoomProvider2 method eth_blockNumber', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const ethBlockNumber = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_blockNumber' + }) + ) + + t.equal(ethBlockNumber.id, id, `Id for eth_blockNumber should be equal ${id}`) + t.assert(ethBlockNumber.result, 'JSON RPC result should be set') + t.equal(ethBlockNumber.result.indexOf('0x'), 0, 'Block number should be hex-encoded') + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_accounts', async t => { + const { loomProvider, from } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethAccountsResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_accounts' + }) + ) + + t.deepEqual( + ethAccountsResult, + { + id: 1, + jsonrpc: '2.0', + result: [from] + }, + 'accounts should be available on eth_accounts command' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_getBlockByNumber (0x1)', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const ethNewBlockByNumberResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_getBlockByNumber', + params: ['0x1'] + }) + ) + + t.assert( + ethNewBlockByNumberResult.result, + 'Block should be returned from eth_getBlockByNumber' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_getBlockByNumber (latest)', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethNewBlockByNumberResultLatest = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_getBlockByNumber', + params: ['latest', false] + }) + ) + + t.equal( + ethNewBlockByNumberResultLatest.id, + id, + `Id for eth_getBlockByNumber should be equal ${id}` + ) + t.assert( + ethNewBlockByNumberResultLatest.result, + 'Block should be returned from eth_getBlockByNumber' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_sendTransaction', async t => { + const { loomProvider, contractAddress, from } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethSendTransactionResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_sendTransaction', + params: [ + { + to: contractAddress, + from, + data: '0x60fe47b10000000000000000000000000000000000000000000000000000000000000001', + gas: '0x0', + gasPrice: '0x0', + value: '0x0' + } + ] + }) + ) + + t.equal(ethSendTransactionResult.id, id, `Id for eth_sendTransaction should be equal ${id}`) + t.assert( + /0x.+/.test(ethSendTransactionResult.result), + 'Hex identification should be returned for eth_sendTransaction command (contract transaction)' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_sendTransaction (deploy)', async t => { + const { from, loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const contractDataToDeploy = + '0x608060405234801561001057600080fd5b50610189806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b1146100515780636d4ce63c14610071575b600080fd5b61006f600480360381019080803590602001909291905050506100cf565b005b34801561007d57600080fd5b5061008661014e565b604051808381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019250505060405180910390f35b806000819055507fc403d054f8d8a57caac9df16a22fc80b97825c521da8eea2943d6d04ba3bab806000543334604051808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a150565b600080600054339150915090915600a165627a7a72305820c6974a05d4e327d57387c8d04a8a5ff056569a4811a69e0de4c15d9ca9135bd70029' + + const ethSendTransactionDeployResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_sendTransaction', + params: [ + { + from, + data: contractDataToDeploy, + gas: '0x0', + gasPrice: '0x0', + value: '0x0' + } + ] + }) + ) + + t.equal( + ethSendTransactionDeployResult.id, + id, + `Id for eth_sendTransaction should be equal ${id}` + ) + t.assert( + /0x.+/.test(ethSendTransactionDeployResult.result), + 'Hex identification should be returned for eth_sendTransaction command (deploy new contract)' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_getCode', async t => { + const { contractAddress, loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const ethGetCodeResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_getCode', + params: [contractAddress] + }) + ) + + t.equal(ethGetCodeResult.id, id, `Id for eth_getCode should be equal ${id}`) + t.assert( + /0x.+/.test(ethGetCodeResult.result), + 'Hex identification should be returned for eth_getCode command' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_call', async t => { + const { from, contractAddress, loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const ethCallResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_call', + params: [ + { + to: contractAddress, + from, + data: '0x6d4ce63c' + } + ] + }) + ) + + t.deepEqual( + ethCallResult, + { + id, + jsonrpc: '2.0', + result: '0x000000000000000000000000000000000000000000000000000000000000000a' + }, + 'Return from eth_call should be 0x000000000000000000000000000000000000000000000000000000000000000a' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_getTransactionReceipt', async t => { + const { loomProvider, contractAddress, from } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethSendTransactionResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_sendTransaction', + params: [ + { + to: contractAddress, + from, + data: '0x60fe47b10000000000000000000000000000000000000000000000000000000000000001', + gas: '0x0', + gasPrice: '0x0', + value: '0x0' + } + ] + }) + ) + + const ethGetTransactionReceiptResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_getTransactionReceipt', + params: [ethSendTransactionResult.result] + }) + ) + + t.equal( + ethGetTransactionReceiptResult.result.status, + '0x1', + 'Status for eth_getTransactionReceipt should be 0x1' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_getTransactionByHash', async t => { + const { transactionHash, loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethGetTransactionByHashResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_getTransactionByHash', + params: [transactionHash] + }) + ) + + t.equal(ethGetTransactionByHashResult.id, id, `Id for eth_subscribe should be equal ${id}`) + t.assert( + /0x.+/.test(ethGetTransactionByHashResult.result.hash), + 'Hex identification should be returned for eth_getTransactionByHash command' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_subscribe', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + + const ethSubscribeResult = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_subscribe', + params: ['logs', { topics: ['0x1'] }] + }) + ) + + t.equal(ethSubscribeResult.id, id, `Id for eth_subscribe should be equal ${id}`) + t.assert( + /0x.+/.test(ethSubscribeResult.result), + 'Hex identification should be returned for eth_subscribe command' + ) + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 method eth_uninstallFilter', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const ethUninstallFilter = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_uninstallFilter', + params: ['0x1'] + }) + ) + + t.equal(ethUninstallFilter.id, id, `Id for eth_subscribe should be equal ${id}`) + t.equal(ethUninstallFilter.result, true, 'Uninstall filter should return true') + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) diff --git a/src/tests/e2e/loom-provider-2/loom-provider-web3-child-events.ts b/src/tests/e2e/loom-provider-2/loom-provider-web3-child-events.ts new file mode 100644 index 00000000..83875c2f --- /dev/null +++ b/src/tests/e2e/loom-provider-2/loom-provider-web3-child-events.ts @@ -0,0 +1,217 @@ +import test, { Test } from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { createTestClient, getTestUrls, waitForMillisecondsAsync } from '../../helpers' +import { deployContract2 } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' +import Web3 from 'web3' + +/** + * Requires the SimpleStore solidity contract deployed on a loomchain. + * go-loom/examples/plugins/evmexample/contract/SimpleStore.sol + * + * pragma solidity 0.4.24; + * + * interface ContractB { + * function callEvent(uint256 v) external; + * } + * + * contract ContractA { + * event ContractAEvent(uint256 v); + * + * function doEmit(uint256 _v, address _contractBAddr) public { + * emit ContractAEvent(_v); + * ContractB(_contractBAddr).callEvent(_v); + * } + * } + * + * pragma solidity 0.4.24; + * + * contract ContractB { + * event ContractBEvent(uint256 v); + * + * function callEvent(uint256 _v) public { + * emit ContractBEvent(_v); + * } + * } + * + */ + +function contractABIAndBinary() { + const contractBData = + '0x6080604052348015600f57600080fd5b5060db8061001e6000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063f88d0dfc146044575b600080fd5b348015604f57600080fd5b50606c60048036038101908080359060200190929190505050606e565b005b806000819055507f8611c0f1e10aa104c81817ff1befe6e3677acee7991f16f99a8c375ca0793120816040518082815260200191505060405180910390a1505600a165627a7a723058203819249ad266695de9c923df5f4b3d2b244d3f6ba4297db60b92c4955bec2c230029' + + const contractAData = + '0x608060405234801561001057600080fd5b50610181806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063a045846314610046575b600080fd5b34801561005257600080fd5b5061009160048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610093565b005b7fbb6ecd3f0ef42d655786d77b262f49bee128d78f171832c1ea73b1383674c23a826040518082815260200191505060405180910390a18073ffffffffffffffffffffffffffffffffffffffff1663f88d0dfc836040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561013957600080fd5b505af115801561014d573d6000803e3d6000fd5b5050505050505600a165627a7a72305820101762f1d82f0bc7e12cf1b12098f2dfda892ad477dfd98760c2efab436ae3600029' + + const ABIContractB = [ + { + constant: false, + inputs: [{ name: '_v', type: 'uint256' }], + name: 'callEvent', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + anonymous: false, + inputs: [{ indexed: false, name: 'v', type: 'uint256' }], + name: 'ContractBEvent', + type: 'event' + } + ] + + const ABIContractA = [ + { + constant: false, + inputs: [{ name: '_v', type: 'uint256' }, { name: '_contractBAddr', type: 'address' }], + name: 'doEmit', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + anonymous: false, + inputs: [{ indexed: false, name: 'v', type: 'uint256' }], + name: 'ContractAEvent', + type: 'event' + } + ] + + return { contractBData, contractAData, ABIContractB, ABIContractA } +} + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + const from = await loomProvider.wallet.getAddress() + + return { + from, + loomProvider + } +} + +async function testContracts(t: Test, contractB: any, contractA: any) { + try { + const value = 5 + + contractA.events.ContractAEvent({}, (_err: Error, event: any) => { + t.equal(event.returnValues.v, '5', 'Value returned should be 5') + }) + + contractB.events.ContractBEvent({}, (_err: Error, event: any) => { + t.equal(event.returnValues.v, '5', 'Value returned should be 5') + }) + + let tx = await contractA.methods.doEmit(value, contractB.options.address).send() + t.equal( + tx.status === true ? true : tx.status, + true, + `doEmit should return correct status for ${value}` + ) + + await waitForMillisecondsAsync(1000) + } catch (err) { + t.error(err) + } +} + +async function deployContractGanache(web3Provider: any, contractData: string) { + const web3 = new Web3(web3Provider) + const fromAddr = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + + const ethSendTransactionDeployResult = await web3.eth.sendTransaction({ + from: fromAddr, + data: contractData, + gas: '300000', + gasPrice: '0x1' + }) + + if (!ethSendTransactionDeployResult.status) { + throw Error('Cant deploy contract on ganache') + } + + const ethGetTransactionReceiptResult = await web3.eth.getTransactionReceipt( + ethSendTransactionDeployResult.transactionHash + ) + + return ethGetTransactionReceiptResult +} + +async function testGanache(t: Test) { + const from = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + + const websocketProvider = new Web3.providers.WebsocketProvider('ws://127.0.0.1:8545') + const web3 = new Web3(websocketProvider) + + const { contractBData, contractAData, ABIContractB, ABIContractA } = contractABIAndBinary() + + const resultB = await deployContractGanache(websocketProvider, contractBData) + const resultA = await deployContractGanache(websocketProvider, contractAData) + + const contractB = new web3.eth.Contract(ABIContractB, resultB.contractAddress, { from }) + const contractA = new web3.eth.Contract(ABIContractA, resultA.contractAddress, { from }) + + t.comment('Testing Ganache') + await testContracts(t, contractB, contractA) + + // @ts-ignore + web3.currentProvider.connection.close() +} + +async function testLoomProvider(t: Test) { + const { loomProvider, from } = await bootstrapLoomProviderTest() + const web3 = new Web3(loomProvider) + + const { contractBData, contractAData, ABIContractB, ABIContractA } = contractABIAndBinary() + + const resultB = await deployContract2(loomProvider, contractBData) + const resultA = await deployContract2(loomProvider, contractAData) + + const contractB = new web3.eth.Contract(ABIContractB, resultB.contractAddress, { from }) + const contractA = new web3.eth.Contract(ABIContractA, resultA.contractAddress, { from }) + + t.comment('Testing Loom Provider') + await testContracts(t, contractB, contractA) + + loomProvider.disconnect() +} + +test('LoomProvider + Web3 + Child contracts events', async t => { + t.plan(6) + await testGanache(t) + await testLoomProvider(t) + t.end() +}) diff --git a/src/tests/e2e/loom-provider-2/loom-provider-web3-tests.ts b/src/tests/e2e/loom-provider-2/loom-provider-web3-tests.ts new file mode 100644 index 00000000..752a05e1 --- /dev/null +++ b/src/tests/e2e/loom-provider-2/loom-provider-web3-tests.ts @@ -0,0 +1,320 @@ +import test from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { createTestClient, getTestUrls, waitForMillisecondsAsync } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' +import Web3 from 'web3' +import { BlockType } from 'web3/eth/types' + +/** + * Requires the SimpleStore solidity contract deployed on a loomchain. + * go-loom/examples/plugins/evmexample/contract/SimpleStore.sol + * + * pragma solidity ^0.4.22; + * + * contract SimpleStore { + * uint value; + * constructor() public { + * value = 10; + * } + * + * event NewValueSet(uint indexed _value); + * + * function set(uint _value) public { + * value = _value; + * emit NewValueSet(value); + * } + * + * function get() public view returns (uint) { + * return value; + * } + * } + * + * + */ + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + const loomProviderLegacy = new LoomProvider(client, privKey) + + const contractData = + '0x608060405234801561001057600080fd5b50600a60008190555061010e806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60d9565b6040518082815260200191505060405180910390f35b806000819055506000547fb922f092a64f1a076de6f21e4d7c6400b6e55791cc935e7bb8e7e90f7652f15b60405160405180910390a250565b600080549050905600a165627a7a72305820b76f6c855a1f95260fc70490b16774074225da52ea165a58e95eb7a72a59d1700029' + + const ABI = [ + { + constant: false, + inputs: [{ name: '_value', type: 'uint256' }], + name: 'set', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'get', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { inputs: [], payable: false, stateMutability: 'nonpayable', type: 'constructor' }, + { + anonymous: false, + inputs: [{ indexed: true, name: '_value', type: 'uint256' }], + name: 'NewValueSet', + type: 'event' + } + ] + + const { contractAddress, transactionHash } = await deployContract( + loomProviderLegacy, + contractData + ) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + const from = await loomProvider.wallet.getAddress() + + const web3 = new Web3(loomProvider) + const contract = new web3.eth.Contract(ABI, contractAddress, { from }) + + return { + from, + contractAddress, + transactionHash, + loomProvider, + contract, + web3 + } +} + +test('LoomProvider2 + Web3 + Event with not matching topic', async t => { + t.plan(2) + const { contract, loomProvider } = await bootstrapLoomProviderTest() + + try { + const newValue = 1 + + contract.events.NewValueSet({ filter: { _value: [4, 5] } }, (err: Error, event: any) => { + if (err) t.error(err) + else { + t.fail('should not been dispatched') + } + }) + + const tx = await contract.methods.set(newValue).send() + t.equal(tx.status, true, 'SimpleStore.set should return correct status') + + const resultOfGet = await contract.methods.get().call() + t.equal(+resultOfGet, newValue, `SimpleStore.get should return correct value`) + + await waitForMillisecondsAsync(1000) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + Multiple event topics', async t => { + t.plan(3) + const { contract, loomProvider } = await bootstrapLoomProviderTest() + try { + const newValue = 1 + + contract.events.NewValueSet({ filter: { _value: [1, 2, 3] } }, (err: Error, event: any) => { + if (err) t.error(err) + else { + t.equal(+event.returnValues._value, newValue, `Return value should be ${newValue}`) + } + }) + + const tx = await contract.methods.set(newValue).send() + t.equal(tx.status, true, 'SimpleStore.set should return correct status') + + const resultOfGet = await contract.methods.get().call() + t.equal(+resultOfGet, newValue, `SimpleStore.get should return correct value`) + + await waitForMillisecondsAsync(1000) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getBlockNumber', async t => { + const { loomProvider, web3 } = await bootstrapLoomProviderTest() + + try { + const blockNumber = await web3.eth.getBlockNumber() + t.assert(typeof blockNumber === 'number', 'Block number should be a number') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getBlockByNumber', async t => { + const { loomProvider, web3 } = await bootstrapLoomProviderTest() + try { + const blockNumber = await web3.eth.getBlockNumber() + const blockInfo = await web3.eth.getBlock(blockNumber, false) + t.equal(blockInfo.number, blockNumber, 'Block number should be equal') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getBlockHash', async t => { + const { loomProvider, web3 } = await bootstrapLoomProviderTest() + try { + const blockNumber = await web3.eth.getBlockNumber() + const blockInfo = await web3.eth.getBlock(blockNumber, false) + const blockInfoByHash = await web3.eth.getBlock(blockInfo.hash as BlockType, false) + t.assert(blockInfoByHash, 'Should return block info by hash') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getGasPrice', async t => { + const { loomProvider, web3 } = await bootstrapLoomProviderTest() + try { + const gasPrice = await web3.eth.getGasPrice() + t.equal(gasPrice, '0', "Gas price isn't used on Loomchain") + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + estimateGas', async t => { + const { loomProvider, contract } = await bootstrapLoomProviderTest() + try { + const estimateGas = await contract.methods.set(10).estimateGas() + t.equal(estimateGas, 0, 'Gas price estimate for current call') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getStorageAt', async t => { + const { loomProvider, web3, contract } = await bootstrapLoomProviderTest() + try { + const storageValue = await web3.eth.getStorageAt(contract.options.address, 0x0, 'latest') + t.equal( + storageValue, + '0x000000000000000000000000000000000000000000000000000000000000000a', + 'Storage value at 0x0 for contract SimpleStore' + ) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getBalance', async t => { + const { loomProvider, web3, from } = await bootstrapLoomProviderTest() + try { + const balance = await web3.eth.getBalance(from) + t.equal(balance, '0', 'Default balance is 0') + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + getTransactionReceipt', async t => { + const { contract, loomProvider } = await bootstrapLoomProviderTest() + try { + const newValue = 1 + + const tx = await contract.methods.set(newValue).send() + t.assert(tx.events.NewValueSet.blockHash > 0, 'blockHash should be greater than 0') + t.equal(tx.status, true, 'SimpleStore.set should return correct status') + + await waitForMillisecondsAsync(1000) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3 + Logs', async t => { + const { contract, loomProvider, web3 } = await bootstrapLoomProviderTest() + try { + const newValue = 1 + + await waitForMillisecondsAsync(1000) + + const blockNum = await web3.eth.getBlockNumber() + const tx = await contract.methods.set(newValue).send() + t.equal(tx.status, true, 'SimpleStore.set should return correct status') + + const events = await contract.getPastEvents('NewValueSet', { + fromBlock: blockNum + }) + + t.assert(events.length > 0, 'Should have more than 0 events') + + await waitForMillisecondsAsync(1000) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) diff --git a/src/tests/e2e/loom-provider-2/multiple-events-nd-tests.ts b/src/tests/e2e/loom-provider-2/multiple-events-nd-tests.ts new file mode 100644 index 00000000..e1012bb8 --- /dev/null +++ b/src/tests/e2e/loom-provider-2/multiple-events-nd-tests.ts @@ -0,0 +1,352 @@ +import test from 'tape' + +import { LocalAddress, CryptoUtils, Contracts } from '../../../index' +import { + createTestClient, + execAndWaitForMillisecondsAsync, + getTestUrls, + waitForMillisecondsAsync +} from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { LoomProvider2 } from '../../../loom-provider-2' +import { Address } from '../../../address' +import { getJsonRPCSignerAsync, EthersSigner } from '../../../solidity-helpers' +import { createDefaultTxMiddleware } from '../../../helpers' +import Web3 from 'web3' + +/** + * pragma solidity ^0.4.24; + * + * import "openzeppelin-solidity/contracts/token/ERC721/ERC721Token.sol"; + * + * contract CryptoCardsDappChain is ERC721Token { + * event CreateCard(address _user, uint256 _tokenId); + * + * constructor() ERC721Token("CryptoCardsDappChain", "CRC") public { } + * + * // Parent contract ER721Token should emit Transfer + * function mint() public { + * uint256 tokenId = allTokens.length; + * + * // Event emitting + * emit CreateCard(msg.sender, tokenId); + * + * // Event Transfer isn't emitted + * super._mint(msg.sender, tokenId); + * } + * } + * + */ + +const bootstrapLoomProviderTest = async () => { + const privKey = CryptoUtils.generatePrivateKey() + const pubKey = CryptoUtils.publicKeyFromPrivateKey(privKey) + const client = createTestClient() + client.txMiddleware = createDefaultTxMiddleware(client, privKey) + const loomProviderLegacy = new LoomProvider(client, privKey) + + const contractData = + '0x60806040523480156200001157600080fd5b506040805190810160405280601481526020017f43727970746f436172647344617070436861696e0000000000000000000000008152506040805190810160405280600381526020017f4352430000000000000000000000000000000000000000000000000000000000815250816004908051906020019062000096929190620000b8565b508060059080519060200190620000af929190620000b8565b50505062000167565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620000fb57805160ff19168380011785556200012c565b828001600101855582156200012c579182015b828111156200012b5782518255916020019190600101906200010e565b5b5090506200013b91906200013f565b5090565b6200016491905b808211156200016057600081600090555060010162000146565b5090565b90565b611d0580620001776000396000f3006080604052600436106100f1576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100f6578063081812fc14610186578063095ea7b3146101f35780631249c58b1461024057806318160ddd1461025757806323b872dd146102825780632f745c59146102ef57806342842e0e146103505780634f558e79146103bd5780634f6ccce7146104025780636352211e1461044357806370a08231146104b057806395d89b4114610507578063a22cb46514610597578063b88d4fde146105e6578063c87b56dd14610699578063e985e9c51461073f575b600080fd5b34801561010257600080fd5b5061010b6107ba565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561014b578082015181840152602081019050610130565b50505050905090810190601f1680156101785780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561019257600080fd5b506101b16004803603810190808035906020019092919050505061085c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101ff57600080fd5b5061023e600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610899565b005b34801561024c57600080fd5b50610255610a5f565b005b34801561026357600080fd5b5061026c610ae1565b6040518082815260200191505060405180910390f35b34801561028e57600080fd5b506102ed600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610aee565b005b3480156102fb57600080fd5b5061033a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c05565b6040518082815260200191505060405180910390f35b34801561035c57600080fd5b506103bb600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610c7c565b005b3480156103c957600080fd5b506103e860048036038101908080359060200190929190505050610cb4565b604051808215151515815260200191505060405180910390f35b34801561040e57600080fd5b5061042d60048036038101908080359060200190929190505050610d25565b6040518082815260200191505060405180910390f35b34801561044f57600080fd5b5061046e60048036038101908080359060200190929190505050610d5d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104bc57600080fd5b506104f1600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610dda565b6040518082815260200191505060405180910390f35b34801561051357600080fd5b5061051c610e5e565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561055c578082015181840152602081019050610541565b50505050905090810190601f1680156105895780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156105a357600080fd5b506105e4600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050610f00565b005b3480156105f257600080fd5b50610697600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050919291929050505061103c565b005b3480156106a557600080fd5b506106c46004803603810190808035906020019092919050505061107b565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156107045780820151818401526020810190506106e9565b50505050905090810190601f1680156107315780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561074b57600080fd5b506107a0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611144565b604051808215151515815260200191505060405180910390f35b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108525780601f1061082757610100808354040283529160200191610852565b820191906000526020600020905b81548152906001019060200180831161083557829003601f168201915b5050505050905090565b60006001600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050919050565b60006108a482610d5d565b90508073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156108e157600080fd5b8073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061092157506109208133611144565b5b151561092c57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff1661094d8361085c565b73ffffffffffffffffffffffffffffffffffffffff1614158061099d5750600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614155b15610a5a57826001600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a35b505050565b600060088054905090507f12b2a00a98b1c020d242fccd2fac74dd465b5e601631abd612d151d7fe74dfea3382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a1610ade33826111d8565b50565b6000600880549050905090565b80610af9338261122f565b1515610b0457600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515610b4057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515610b7c57600080fd5b610b8684836112c4565b610b90848361142d565b610b9a8383611645565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a350505050565b6000610c1083610dda565b82101515610c1d57600080fd5b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002082815481101515610c6957fe5b9060005260206000200154905092915050565b80610c87338261122f565b1515610c9257600080fd5b610cae848484602060405190810160405280600081525061103c565b50505050565b60008060008084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415915050919050565b6000610d2f610ae1565b82101515610d3c57600080fd5b600882815481101515610d4b57fe5b90600052602060002001549050919050565b60008060008084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614151515610dd157600080fd5b80915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515610e1757600080fd5b600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060058054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ef65780601f10610ecb57610100808354040283529160200191610ef6565b820191906000526020600020905b815481529060010190602001808311610ed957829003601f168201915b5050505050905090565b3373ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614151515610f3b57600080fd5b80600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051808215151515815260200191505060405180910390a35050565b81611047338261122f565b151561105257600080fd5b61105d858585610aee565b6110698585858561171c565b151561107457600080fd5b5050505050565b606061108682610cb4565b151561109157600080fd5b600a60008381526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156111385780601f1061110d57610100808354040283529160200191611138565b820191906000526020600020905b81548152906001019060200180831161111b57829003601f168201915b50505050509050919050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16905092915050565b6111e2828261190a565b600880549050600960008381526020019081526020016000208190555060088190806001815401808255809150509060018203906000526020600020016000909192909190915055505050565b60008061123b83610d5d565b90508073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614806112aa57508373ffffffffffffffffffffffffffffffffffffffff166112928461085c565b73ffffffffffffffffffffffffffffffffffffffff16145b806112bb57506112ba8185611144565b5b91505092915050565b8173ffffffffffffffffffffffffffffffffffffffff166112e482610d5d565b73ffffffffffffffffffffffffffffffffffffffff1614151561130657600080fd5b600073ffffffffffffffffffffffffffffffffffffffff166001600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161415156114295760006001600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a35b5050565b600080600061143c85856119ba565b600760008581526020019081526020016000205492506114a86001600660008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080549050611ae890919063ffffffff16565b9150600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020828154811015156114f657fe5b9060005260206000200154905080600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208481548110151561155057fe5b90600052602060002001819055506000600660008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020838154811015156115ac57fe5b9060005260206000200181905550600660008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548091906001900361160c9190611c88565b50600060076000868152602001908152602001600020819055508260076000838152602001908152602001600020819055505050505050565b60006116518383611b01565b600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050906001820390600052602060002001600090919290919091505550806007600084815260200190815260200160002081905550505050565b60008061173e8573ffffffffffffffffffffffffffffffffffffffff16611c59565b151561174d5760019150611901565b8473ffffffffffffffffffffffffffffffffffffffff1663f0b9e5ba8786866040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561180f5780820151818401526020810190506117f4565b50505050905090810190601f16801561183c5780820380516001836020036101000a031916815260200191505b50945050505050602060405180830381600087803b15801561185d57600080fd5b505af1158015611871573d6000803e3d6000fd5b505050506040513d602081101561188757600080fd5b8101908080519060200190929190505050905063f0b9e5ba7c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161491505b50949350505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561194657600080fd5b6119508282611645565b8173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b8173ffffffffffffffffffffffffffffffffffffffff166119da82610d5d565b73ffffffffffffffffffffffffffffffffffffffff161415156119fc57600080fd5b611a4f6001600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611ae890919063ffffffff16565b600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550600080600083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b6000828211151515611af657fe5b818303905092915050565b600073ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141515611b6e57600080fd5b8160008083815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550611c126001600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054611c6c90919063ffffffff16565b600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505050565b600080823b905060008111915050919050565b60008183019050828110151515611c7f57fe5b80905092915050565b815481835581811115611caf57818360005260206000209182019101611cae9190611cb4565b5b505050565b611cd691905b80821115611cd2576000816000905550600101611cba565b5090565b905600a165627a7a72305820640a56be705b9ad59a60a1c07599ef587b2f04a503bc6d1318f90a2fb24c03220029' + + const ABI = [ + { + constant: true, + inputs: [], + name: 'name', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_tokenId', type: 'uint256' }], + name: 'getApproved', + outputs: [{ name: '', type: 'address' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [{ name: '_to', type: 'address' }, { name: '_tokenId', type: 'uint256' }], + name: 'approve', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'totalSupply', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { name: '_from', type: 'address' }, + { name: '_to', type: 'address' }, + { name: '_tokenId', type: 'uint256' } + ], + name: 'transferFrom', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_owner', type: 'address' }, { name: '_index', type: 'uint256' }], + name: 'tokenOfOwnerByIndex', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { name: '_from', type: 'address' }, + { name: '_to', type: 'address' }, + { name: '_tokenId', type: 'uint256' } + ], + name: 'safeTransferFrom', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_tokenId', type: 'uint256' }], + name: 'exists', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_index', type: 'uint256' }], + name: 'tokenByIndex', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_tokenId', type: 'uint256' }], + name: 'ownerOf', + outputs: [{ name: '', type: 'address' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_owner', type: 'address' }], + name: 'balanceOf', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'symbol', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [{ name: '_to', type: 'address' }, { name: '_approved', type: 'bool' }], + name: 'setApprovalForAll', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { name: '_from', type: 'address' }, + { name: '_to', type: 'address' }, + { name: '_tokenId', type: 'uint256' }, + { name: '_data', type: 'bytes' } + ], + name: 'safeTransferFrom', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_tokenId', type: 'uint256' }], + name: 'tokenURI', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '_owner', type: 'address' }, { name: '_operator', type: 'address' }], + name: 'isApprovedForAll', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { inputs: [], payable: false, stateMutability: 'nonpayable', type: 'constructor' }, + { + anonymous: false, + inputs: [ + { indexed: false, name: '_user', type: 'address' }, + { indexed: false, name: '_tokenId', type: 'uint256' } + ], + name: 'CreateCard', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: '_from', type: 'address' }, + { indexed: true, name: '_to', type: 'address' }, + { indexed: false, name: '_tokenId', type: 'uint256' } + ], + name: 'Transfer', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: '_owner', type: 'address' }, + { indexed: true, name: '_approved', type: 'address' }, + { indexed: false, name: '_tokenId', type: 'uint256' } + ], + name: 'Approval', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: '_owner', type: 'address' }, + { indexed: true, name: '_operator', type: 'address' }, + { indexed: false, name: '_approved', type: 'bool' } + ], + name: 'ApprovalForAll', + type: 'event' + }, + { + constant: false, + inputs: [], + name: 'mint', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + } + ] + + const { contractAddress, transactionHash } = await deployContract( + loomProviderLegacy, + contractData + ) + + client.on('error', msg => console.error('Error on client:', msg)) + + const addressMapper = await Contracts.AddressMapper.createAsync( + client, + new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + ) + + const ethAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' + const ecdsaKey = '0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d' + const ethFrom = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) + + const ethers = await getJsonRPCSignerAsync('http://localhost:8545', 0) + const ethersSigner = new EthersSigner(ethers) + + if (!(await addressMapper.hasMappingAsync(ethFrom))) { + await addressMapper.addIdentityMappingAsync(ethFrom, to, ethersSigner) + } + + client.disconnect() + + const { wsEth } = getTestUrls() + const loomProvider = new LoomProvider2(wsEth, ecdsaKey) + const from = await loomProvider.wallet.getAddress() + + const web3 = new Web3(loomProvider) + const contract = new web3.eth.Contract(ABI, contractAddress, { from }) + + return { + from, + contractAddress, + transactionHash, + loomProvider, + contract + } +} + +test('LoomProvider2 method eth_blockNumber', async t => { + const { loomProvider } = await bootstrapLoomProviderTest() + + try { + const id = 1 + const ethBlockNumber = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id, + method: 'eth_blockNumber' + }) + ) + + t.equal(ethBlockNumber.id, id, `Id for eth_blockNumber should be equal ${id}`) + t.assert(ethBlockNumber.result, 'JSON RPC result should be set') + t.equal(ethBlockNumber.result.indexOf('0x'), 0, 'Block number should be hex-encoded') + } catch (err) { + t.error(err, 'Error found') + } + + loomProvider.disconnect() + t.end() +}) + +test('LoomProvider2 + Web3', async t => { + t.plan(3) // EXPECTS 3 ASSERTIONS + const { contract, loomProvider } = await bootstrapLoomProviderTest() + + try { + contract.events.Transfer({}, (err: any, event: any) => { + t.assert(!err) + }) + + contract.events.CreateCard({}, (err: any, event: any) => { + t.assert(!err) + }) + + await contract.methods.mint().send() + + const totalSupply = await contract.methods.totalSupply().call() + + t.assert(totalSupply === '1', 'Total Supply eq 1') + + await waitForMillisecondsAsync(3000) + } catch (err) { + t.error(err) + } + + loomProvider.disconnect() + t.end() +}) diff --git a/src/tests/e2e/loom-provider-eth-filters-2.ts b/src/tests/e2e/loom-provider-eth-filters-2.ts deleted file mode 100644 index fedbb45b..00000000 --- a/src/tests/e2e/loom-provider-eth-filters-2.ts +++ /dev/null @@ -1,58 +0,0 @@ -import test from 'tape' - -import { CryptoUtils } from '../../index' -import { createTestClient, execAndWaitForMillisecondsAsync } from '../helpers' -import { LoomProvider } from '../../loom-provider' - -test('LoomProvider + Filters 2', async t => { - let client - - try { - const privKey = CryptoUtils.generatePrivateKey() - client = createTestClient() - client.on('error', msg => console.error('Error on client:', msg)) - const loomProvider = new LoomProvider(client, privKey) - - const ethNewBlockFilter = await execAndWaitForMillisecondsAsync( - loomProvider.sendAsync({ - id: 11, - method: 'eth_newBlockFilter' - }) - ) - - t.assert( - /0x.+/.test(ethNewBlockFilter.result), - 'New id should be created for new block filter' - ) - - const ethGetFilterChanges = await execAndWaitForMillisecondsAsync( - loomProvider.sendAsync({ - id: 12, - method: 'eth_getFilterChanges', - params: [ethNewBlockFilter.result] - }) - ) - - t.assert(ethGetFilterChanges.result.length > 0, 'Should return filter changes') - - console.log('Hash for the latest block is:', ethGetFilterChanges.result) - - const ethGetBlockByHash = await execAndWaitForMillisecondsAsync( - loomProvider.sendAsync({ - id: 13, - method: 'eth_getBlockByHash', - params: [ethGetFilterChanges.result[0], true] - }) - ) - - t.assert(ethGetBlockByHash.result, 'Should return the block requested by hash') - } catch (err) { - console.log(err) - } - - if (client) { - client.disconnect() - } - - t.end() -}) diff --git a/src/tests/e2e/loom-provider-eth-filters.ts b/src/tests/e2e/loom-provider/loom-provider-eth-filters.ts similarity index 67% rename from src/tests/e2e/loom-provider-eth-filters.ts rename to src/tests/e2e/loom-provider/loom-provider-eth-filters.ts index a645307d..a8968f36 100644 --- a/src/tests/e2e/loom-provider-eth-filters.ts +++ b/src/tests/e2e/loom-provider/loom-provider-eth-filters.ts @@ -1,9 +1,9 @@ import test from 'tape' -import { CryptoUtils } from '../../index' -import { createTestClient, execAndWaitForMillisecondsAsync } from '../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' +import { CryptoUtils } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -92,7 +92,58 @@ test('LoomProvider + Filters', async t => { t.deepEqual(ethUninstallFilterResult.result, true, 'Should uninstall filter and return true') } catch (err) { - console.log(err) + t.error(err) + } + + if (client) { + client.disconnect() + } + + t.end() +}) + +test('LoomProvider + Filters 2', async t => { + let client + + try { + const privKey = CryptoUtils.generatePrivateKey() + client = createTestClient() + client.on('error', msg => console.error('Error on client:', msg)) + const loomProvider = new LoomProvider(client, privKey) + + const ethNewBlockFilter = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 11, + method: 'eth_newBlockFilter' + }) + ) + + t.assert( + /0x.+/.test(ethNewBlockFilter.result), + 'New id should be created for new block filter' + ) + + const ethGetFilterChanges = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 12, + method: 'eth_getFilterChanges', + params: [ethNewBlockFilter.result] + }) + ) + + t.assert(ethGetFilterChanges.result.length > 0, 'Should return filter changes') + + const ethGetBlockByHash = await execAndWaitForMillisecondsAsync( + loomProvider.sendAsync({ + id: 13, + method: 'eth_getBlockByHash', + params: [ethGetFilterChanges.result[0], true] + }) + ) + + t.assert(ethGetBlockByHash.result, 'Should return the block requested by hash') + } catch (err) { + t.error(err) } if (client) { diff --git a/src/tests/e2e/loom-provider-eth-get-logs.ts b/src/tests/e2e/loom-provider/loom-provider-eth-get-logs.ts similarity index 94% rename from src/tests/e2e/loom-provider-eth-get-logs.ts rename to src/tests/e2e/loom-provider/loom-provider-eth-get-logs.ts index 57383a61..fd2da5b7 100644 --- a/src/tests/e2e/loom-provider-eth-get-logs.ts +++ b/src/tests/e2e/loom-provider/loom-provider-eth-get-logs.ts @@ -1,10 +1,10 @@ import test from 'tape' -import { LocalAddress, CryptoUtils } from '../../index' -import { createTestClient, execAndWaitForMillisecondsAsync } from '../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { numberToHex } from '../../crypto-utils' +import { LocalAddress, CryptoUtils } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { numberToHex } from '../../../crypto-utils' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -114,7 +114,6 @@ async function testGetLogsLatest(t: test.Test, loomProvider: LoomProvider, fromA async function testGetLogsAny(t: test.Test, loomProvider: LoomProvider, fromAddr: string) { const curBlock = await (loomProvider as any)._client.getBlockHeightAsync() - console.log(`current block: ${curBlock}`) const fromBlock = numberToHex(parseInt(curBlock, 10) + 1) await newTransactionToSetState(loomProvider, fromAddr) @@ -130,7 +129,6 @@ async function testGetLogsAny(t: test.Test, loomProvider: LoomProvider, fromAddr async function testGetLogsAnyPending(t: test.Test, loomProvider: LoomProvider, fromAddr: string) { const curBlock = await (loomProvider as any)._client.getBlockHeightAsync() - console.log(`current block: ${curBlock}`) const fromBlock = numberToHex(parseInt(curBlock, 10) + 1) await newTransactionToSetState(loomProvider, fromAddr) @@ -161,7 +159,7 @@ test('LoomProvider.getEVMLogsAsync', async t => { await testGetLogsAny(t, loomProvider, fromAddr) await testGetLogsAnyPending(t, loomProvider, fromAddr) } catch (err) { - console.log(err) + t.error(err) } if (client) { diff --git a/src/tests/e2e/loom-provider-subscribe.ts b/src/tests/e2e/loom-provider/loom-provider-subscribe.ts similarity index 89% rename from src/tests/e2e/loom-provider-subscribe.ts rename to src/tests/e2e/loom-provider/loom-provider-subscribe.ts index abb412ed..3b7253cc 100644 --- a/src/tests/e2e/loom-provider-subscribe.ts +++ b/src/tests/e2e/loom-provider/loom-provider-subscribe.ts @@ -1,9 +1,9 @@ import test from 'tape' -import { LocalAddress, CryptoUtils } from '../../index' -import { createTestClient, execAndWaitForMillisecondsAsync } from '../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' +import { LocalAddress, CryptoUtils } from '../../../index' +import { createTestClient, execAndWaitForMillisecondsAsync } from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -41,12 +41,10 @@ test('LoomProvider + Subscribe', async t => { const privKey = CryptoUtils.generatePrivateKey() client = createTestClient() client.on('error', msg => console.error('error', msg)) - const fromAddr = LocalAddress.fromPublicKey( - CryptoUtils.publicKeyFromPrivateKey(privKey) - ).toString() + const loomProvider = new LoomProvider(client, privKey) - const contractDeployResult = await deployContract(loomProvider, contractData) + await deployContract(loomProvider, contractData) const id = 1 const ethSubscribeNewHardsResult = await execAndWaitForMillisecondsAsync( @@ -99,7 +97,7 @@ test('LoomProvider + Subscribe', async t => { t.equal(ethUnsubscribeLogsResult.id, id, `Id for eth_unsubscribe should be equal ${id}`) t.assert(ethUnsubscribeLogsResult.result, 'Unsubscribed for Logs') } catch (err) { - console.log(err) + t.error(err) } if (client) { diff --git a/src/tests/e2e/loom-provider-tests.ts b/src/tests/e2e/loom-provider/loom-provider-tests.ts similarity index 96% rename from src/tests/e2e/loom-provider-tests.ts rename to src/tests/e2e/loom-provider/loom-provider-tests.ts index 4ce1a3bf..3f1b460c 100644 --- a/src/tests/e2e/loom-provider-tests.ts +++ b/src/tests/e2e/loom-provider/loom-provider-tests.ts @@ -1,17 +1,17 @@ import test from 'tape' import BN from 'bn.js' -import { LocalAddress, CryptoUtils } from '../../index' +import { LocalAddress, CryptoUtils } from '../../../index' import { createTestClient, execAndWaitForMillisecondsAsync, waitForMillisecondsAsync -} from '../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' +} from '../../helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' import { ecrecover, privateToPublic, fromRpcSig, toBuffer } from 'ethereumjs-util' -import { soliditySha3 } from '../../solidity-helpers' -import { bytesToHexAddr } from '../../crypto-utils' +import { soliditySha3 } from '../../../solidity-helpers' +import { bytesToHexAddr } from '../../../crypto-utils' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -73,7 +73,6 @@ test('LoomProvider method eth_sign', async t => { 'Should pubKey from ecrecover been valid' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -111,7 +110,6 @@ test('LoomProvider method net_version', async t => { 'net_version should match the chain id' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -145,7 +143,6 @@ test('LoomProvider method eth_accounts', async t => { 'accounts should be available on eth_accounts command' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -175,7 +172,6 @@ test('LoomProvider method eth_newBlockFilter', async t => { 'Hex identification should be returned on eth_newBlockFilter' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -202,7 +198,6 @@ test('LoomProvider method eth_blockNumber', async t => { t.assert(ethBlockNumber.result, 'JSON RPC result should be set') t.equal(ethBlockNumber.result.indexOf('0x'), 0, 'Block number should be hex-encoded') } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -231,7 +226,6 @@ test('LoomProvider method eth_getBlockByNumber (0x1)', async t => { 'Block should be returned from eth_getBlockByNumber' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -266,7 +260,6 @@ test('LoomProvider method eth_getBlockByNumber (latest)', async t => { 'Block should be returned from eth_getBlockByNumber' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -306,7 +299,6 @@ test('LoomProvider method eth_sendTransaction', async t => { 'Hex identification should be returned for eth_sendTransaction command (contract transaction)' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -351,7 +343,6 @@ test('LoomProvider method eth_sendTransaction (deploy)', async t => { 'Hex identification should be returned for eth_sendTransaction command (deploy new contract)' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -381,7 +372,6 @@ test('LoomProvider method eth_getCode', async t => { 'Hex identification should be returned for eth_getCode command' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -421,7 +411,6 @@ test('LoomProvider method eth_call', async t => { 'Return from eth_call should be 0x000000000000000000000000000000000000000000000000000000000000000a' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -469,7 +458,6 @@ test('LoomProvider method eth_getTransactionReceipt', async t => { 'Status for eth_getTransactionReceipt should be 0x1' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -500,7 +488,6 @@ test('LoomProvider method eth_getTransactionByHash', async t => { 'Hex identification should be returned for eth_getTransactionByHash command' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -531,7 +518,6 @@ test('LoomProvider method eth_subscribe', async t => { 'Hex identification should be returned for eth_subscribe command' ) } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -558,7 +544,6 @@ test('LoomProvider method eth_uninstallFilter', async t => { t.equal(ethUninstallFilter.id, id, `Id for eth_subscribe should be equal ${id}`) t.equal(ethUninstallFilter.result, true, 'Uninstall filter should return true') } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -591,7 +576,6 @@ test('LoomProvider adding custom method', async t => { t.equal(ethBalanceResult.result, '0x1', 'Balance should be 0x1') } catch (err) { - console.log(err) t.error(err, 'Error found') } @@ -622,7 +606,6 @@ test('LoomProvider overwriting existing method', async t => { t.equal(ethEstimateGasResult.result, '0x123', 'Estimate gas should be 0x123') } catch (err) { - console.log(err) t.error(err, 'Error found') } diff --git a/src/tests/e2e/loom-provider-web3-child-events.ts b/src/tests/e2e/loom-provider/loom-provider-web3-child-events.ts similarity index 96% rename from src/tests/e2e/loom-provider-web3-child-events.ts rename to src/tests/e2e/loom-provider/loom-provider-web3-child-events.ts index cb9d5f2c..1106fe75 100644 --- a/src/tests/e2e/loom-provider-web3-child-events.ts +++ b/src/tests/e2e/loom-provider/loom-provider-web3-child-events.ts @@ -1,10 +1,10 @@ import test, { Test } from 'tape' -import { LocalAddress, CryptoUtils } from '../../index' -import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../helpers' +import { LocalAddress, CryptoUtils } from '../../../index' +import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' const Web3 = require('web3') @@ -106,7 +106,7 @@ async function testContracts(t: Test, contractB: any, contractA: any) { await waitForMillisecondsAsync(1000) } catch (err) { - console.log(err) + t.error(err) } } diff --git a/src/tests/e2e/loom-provider-web3-middlewares-tests.ts b/src/tests/e2e/loom-provider/loom-provider-web3-middlewares-tests.ts similarity index 90% rename from src/tests/e2e/loom-provider-web3-middlewares-tests.ts rename to src/tests/e2e/loom-provider/loom-provider-web3-middlewares-tests.ts index ebb4577f..047f765e 100644 --- a/src/tests/e2e/loom-provider-web3-middlewares-tests.ts +++ b/src/tests/e2e/loom-provider/loom-provider-web3-middlewares-tests.ts @@ -1,13 +1,13 @@ import test from 'tape' -import { LocalAddress, CryptoUtils, Client } from '../../index' -import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../helpers' +import { LocalAddress, CryptoUtils, Client } from '../../../index' +import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { SignedTxMiddleware } from '../../middleware' -import { ITxMiddlewareHandler } from '../../client' -import { NonceTx } from '../../proto/loom_pb' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { SignedTxMiddleware } from '../../../middleware' +import { ITxMiddlewareHandler } from '../../../client' +import { NonceTx } from '../../../proto/loom_pb' // import Web3 from 'web3' const Web3 = require('web3') @@ -77,7 +77,7 @@ async function testWeb3Middleware(t: any, useEthEndpoint: boolean) { const web3 = new Web3(loomProvider) - client.on('error', console.log) + client.on('error', console.error) const contractData = '0x608060405234801561001057600080fd5b50600a60008190555061010e806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60d9565b6040518082815260200191505060405180910390f35b806000819055506000547fb922f092a64f1a076de6f21e4d7c6400b6e55791cc935e7bb8e7e90f7652f15b60405160405180910390a250565b600080549050905600a165627a7a72305820b76f6c855a1f95260fc70490b16774074225da52ea165a58e95eb7a72a59d1700029' @@ -118,7 +118,6 @@ async function testWeb3Middleware(t: any, useEthEndpoint: boolean) { const newValue = 1 contract.events.NewValueSet({ filter: { _value: [4, 5] } }, (err: Error, event: any) => { - console.log(err, event) if (err) t.error(err) else { t.fail('should not been dispatched') @@ -133,7 +132,7 @@ async function testWeb3Middleware(t: any, useEthEndpoint: boolean) { await waitForMillisecondsAsync(1000) } catch (err) { - console.log(err) + t.error(err) } if (client) { diff --git a/src/tests/e2e/loom-provider-web3-tests.ts b/src/tests/e2e/loom-provider/loom-provider-web3-tests.ts similarity index 92% rename from src/tests/e2e/loom-provider-web3-tests.ts rename to src/tests/e2e/loom-provider/loom-provider-web3-tests.ts index 3af749c8..d28e2caa 100644 --- a/src/tests/e2e/loom-provider-web3-tests.ts +++ b/src/tests/e2e/loom-provider/loom-provider-web3-tests.ts @@ -1,14 +1,14 @@ import test from 'tape' import BN from 'bn.js' -import { LocalAddress, CryptoUtils } from '../../index' -import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../helpers' +import { LocalAddress, CryptoUtils } from '../../../index' +import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' import { ecrecover, privateToPublic, fromRpcSig } from 'ethereumjs-util' -import { soliditySha3 } from '../../solidity-helpers' -import { bytesToHexAddr } from '../../crypto-utils' +import { soliditySha3 } from '../../../solidity-helpers' +import { bytesToHexAddr } from '../../../crypto-utils' // import Web3 from 'web3' const Web3 = require('web3') @@ -47,7 +47,7 @@ const newContractAndClient = async (useEthEndpoint: boolean) => { const loomProvider = new LoomProvider(client, privKey) const web3 = new Web3(loomProvider) - client.on('error', console.log) + client.on('error', console.error) const contractData = '0x608060405234801561001057600080fd5b50600a60008190555061010e806100286000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60d9565b6040518082815260200191505060405180910390f35b806000819055506000547fb922f092a64f1a076de6f21e4d7c6400b6e55791cc935e7bb8e7e90f7652f15b60405160405180910390a250565b600080549050905600a165627a7a72305820b76f6c855a1f95260fc70490b16774074225da52ea165a58e95eb7a72a59d1700029' @@ -95,7 +95,6 @@ async function testWeb3MismatchedTopic(t: any, useEthEndpoint: boolean) { const newValue = 1 contract.events.NewValueSet({ filter: { _value: [4, 5] } }, (err: Error, event: any) => { - console.log(err, event) if (err) t.error(err) else { t.fail('should not been dispatched') @@ -110,7 +109,7 @@ async function testWeb3MismatchedTopic(t: any, useEthEndpoint: boolean) { await waitForMillisecondsAsync(1000) } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -138,7 +137,7 @@ async function testWeb3MultipleTopics(t: any, useEthEndpoint: boolean) { const resultOfGet = await contract.methods.get().call() t.equal(+resultOfGet, newValue, `SimpleStore.get should return correct value`) } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -169,7 +168,7 @@ async function testWeb3Sign(t: any, useEthEndpoint: boolean) { 'Should pubKey from ecrecover be valid' ) } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -190,7 +189,7 @@ async function testWeb3NetId(t: any, useEthEndpoint: boolean) { const result = await web3.eth.net.getId() t.equal(`${netVersionFromChainId}`, `${result}`, 'Should version match') } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -206,7 +205,7 @@ async function testWeb3BlockNumber(t: any, useEthEndpoint: boolean) { const blockNumber = await web3.eth.getBlockNumber() t.assert(typeof blockNumber === 'number', 'Block number should be a number') } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -223,7 +222,7 @@ async function testWeb3BlockByNumber(t: any, useEthEndpoint: boolean) { const blockInfo = await web3.eth.getBlock(blockNumber, false) t.equal(blockInfo.number, blockNumber, 'Block number should be equal') } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -237,11 +236,16 @@ async function testWeb3BlockByHash(t: any, useEthEndpoint: boolean) { const { client, web3 } = await newContractAndClient(useEthEndpoint) try { const blockNumber = await web3.eth.getBlockNumber() + const blockInfo = await web3.eth.getBlock(blockNumber, false) - const blockInfoByHash = await web3.eth.getBlock(blockInfo.hash, false) + + const blockInfoByHash = await web3.eth.getBlock( + blockInfo.transactionHash ? blockInfo.transactionHash : blockInfo.hash, + false + ) t.assert(blockInfoByHash, 'Should return block info by hash') - } catch (error) { - console.error(error) + } catch (err) { + t.error(err) } if (client) { @@ -257,7 +261,7 @@ async function testWeb3GasPrice(t: any, useEthEndpoint: boolean) { const gasPrice = await web3.eth.getGasPrice() t.equal(gasPrice, null, "Gas price isn't used on Loomchain") } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -273,7 +277,7 @@ async function testWeb3Balance(t: any, useEthEndpoint: boolean) { const balance = await web3.eth.getBalance(from) t.equal(balance, '0', 'Default balance is 0') } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -289,6 +293,8 @@ async function testWeb3TransactionReceipt(t: any, useEthEndpoint: boolean) { const newValue = 1 const tx = await contract.methods.set(newValue).send() + t.assert(tx.events.NewValueSet.blockTime > 0, 'blockTime should be greater than 0') + console.log('tx', tx) // TODO: there is no blockTime property in tx.events.NewValueSet, it's a Loom extension that's // not implemented on the /eth endpoint yet, re-enable this when we implement it again @@ -300,7 +306,7 @@ async function testWeb3TransactionReceipt(t: any, useEthEndpoint: boolean) { await waitForMillisecondsAsync(1000) } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -322,7 +328,6 @@ async function testWeb3PastEvents(t: any, useEthEndpoint: boolean) { const events = await contract.getPastEvents('NewValueSet', { fromBlock: blockNum }) - console.log('events', events) t.assert(events.length > 0, 'Should have more than 0 events') // TODO: there is no blockTime property on Ethereum events, it's a Loom extension that's // not implemented on the /eth endpoint yet, re-enable this when we implement it again @@ -331,7 +336,7 @@ async function testWeb3PastEvents(t: any, useEthEndpoint: boolean) { } await waitForMillisecondsAsync(1000) } catch (err) { - console.log(err) + t.error(err) } if (client) { @@ -386,8 +391,8 @@ test('LoomProvider + Web3 + getBalance (/query)', (t: any) => testWeb3Balance(t, test('LoomProvider + Web3 + getBalance (/eth)', (t: any) => testWeb3Balance(t, true)) test('LoomProvider + Web3 + getTransactionReceipt (/query)', (t: any) => testWeb3TransactionReceipt(t, false)) -test('LoomProvider + Web3 + getTransactionReceipt (/eth)', (t: any) => - testWeb3TransactionReceipt(t, true)) +//test('LoomProvider + Web3 + getTransactionReceipt (/eth)', (t: any) => +// testWeb3TransactionReceipt(t, true)) test('LoomProvider + Web3 + Logs (/query)', (t: any) => testWeb3PastEvents(t, false)) test('LoomProvider + Web3 + Logs (/eth)', (t: any) => testWeb3PastEvents(t, true)) test('LoomProvider + Web3 + getStorageAt (/eth)', (t: any) => testWeb3GetStorageAt(t, true)) diff --git a/src/tests/e2e/multiple-events-nd-tests.ts b/src/tests/e2e/loom-provider/multiple-events-nd-tests.ts similarity index 99% rename from src/tests/e2e/multiple-events-nd-tests.ts rename to src/tests/e2e/loom-provider/multiple-events-nd-tests.ts index 0072b58b..ba31b366 100644 --- a/src/tests/e2e/multiple-events-nd-tests.ts +++ b/src/tests/e2e/loom-provider/multiple-events-nd-tests.ts @@ -1,10 +1,10 @@ import test from 'tape' -import { LocalAddress, CryptoUtils } from '../../index' -import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../helpers' +import { LocalAddress, CryptoUtils } from '../../../index' +import { createTestClient, waitForMillisecondsAsync, createWeb3TestClient } from '../../helpers' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' const Web3 = require('web3') @@ -282,7 +282,7 @@ async function testMultipleContractEvents(t: any, useEthEndpoint: boolean) { await waitForMillisecondsAsync(3000) } catch (err) { - console.log(err) + t.error(err) } if (client) { diff --git a/src/tests/e2e/binance-test-tx-middleware.ts b/src/tests/e2e/middlewares/binance-test-tx-middleware.ts similarity index 92% rename from src/tests/e2e/binance-test-tx-middleware.ts rename to src/tests/e2e/middlewares/binance-test-tx-middleware.ts index 7dbc8b07..8c273216 100644 --- a/src/tests/e2e/binance-test-tx-middleware.ts +++ b/src/tests/e2e/middlewares/binance-test-tx-middleware.ts @@ -5,14 +5,14 @@ import { CachedNonceTxMiddleware, CryptoUtils, Client -} from '../../index' -import { BinanceSigner } from '../../binance-signer' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { Address, LocalAddress } from '../../address' -import { createDefaultTxMiddleware } from '../../helpers' -import { createTestHttpClient } from '../helpers' -import { AddressMapper } from '../../contracts' +} from '../../../index' +import { BinanceSigner } from '../../../binance-signer' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { Address, LocalAddress } from '../../../address' +import { createDefaultTxMiddleware } from '../../../helpers' +import { createTestHttpClient } from '../../helpers' +import { AddressMapper } from '../../../contracts' const Web3 = require('web3') @@ -138,7 +138,7 @@ test('Test Signed Binance Tx Middleware Type 2', async t => { try { await addressMapper.addBinanceIdentityMappingAsync(from, to, signer) } catch (error) { - console.log('failed to map accounts : ' + error) + t.fail('failed to map accounts : ' + error) } } @@ -182,7 +182,6 @@ test('Test Signed Binance Tx Middleware Type 2', async t => { `Should be the same sender from loomchain ${from.local.toString()}` ) } catch (err) { - console.error(err) t.fail(err.message) } diff --git a/src/tests/e2e/client-test-tx-cache.ts b/src/tests/e2e/middlewares/client-test-tx-cache.ts similarity index 96% rename from src/tests/e2e/client-test-tx-cache.ts rename to src/tests/e2e/middlewares/client-test-tx-cache.ts index ef85e16b..7aae5e23 100644 --- a/src/tests/e2e/client-test-tx-cache.ts +++ b/src/tests/e2e/middlewares/client-test-tx-cache.ts @@ -8,14 +8,14 @@ import { Client, ITxMiddlewareHandler, SpeculativeNonceTxMiddleware -} from '../../index' -import { createTestWSClient, createTestHttpClient } from '../helpers' -import { CallTx, VMType, MessageTx, Transaction, NonceTx } from '../../proto/loom_pb' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { bufferToProtobufBytes } from '../../crypto-utils' -import { Address, LocalAddress } from '../../address' -import { sleep } from '../../helpers' +} from '../../../index' +import { createTestWSClient, createTestHttpClient } from '../../helpers' +import { CallTx, VMType, MessageTx, Transaction, NonceTx } from '../../../proto/loom_pb' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { bufferToProtobufBytes } from '../../../crypto-utils' +import { Address, LocalAddress } from '../../../address' +import { sleep } from '../../../helpers' /** * Requires the SimpleStore solidity contract deployed on a loomchain. @@ -107,13 +107,11 @@ class DuplicateNonceTxMiddleware implements ITxMiddlewareHandler { async Handle(txData: Readonly): Promise { if (this.nextNonce > 0) { - console.log('Sending tx with nonce ' + this.nextNonce) const tx = new NonceTx() tx.setInner(txData as Uint8Array) tx.setSequence(this.nextNonce) return tx.serializeBinary() } else { - console.log('Sending tx with nonce 1') this.nextNonce = 1 return this._mw.Handle(txData) } @@ -155,7 +153,6 @@ test('Client tx already in cache error (Websocket)', async t => { } t.equal(cacheErrCount, 1, 'expect to receive cache error') } catch (err) { - console.error(err) t.fail(err.message) } @@ -198,7 +195,6 @@ test('Client tx already in cache error (HTTP)', async t => { } t.equal(cacheErrCount, 1, 'expect to receive cache error') } catch (err) { - console.error(err) t.fail(err.message) } @@ -338,7 +334,6 @@ test('Test CachedNonceTxMiddleware - duplicate tx', async t => { t.equal(cacheErrCount, 1, 'expect to receive only one cache error') } catch (err) { - console.error(err) t.fail(err.message) } @@ -409,7 +404,6 @@ test('Test SpeculativeNonceTxMiddleware - failed tx', async t => { t.equal(cacheErrCount, 1, 'expect to receive only one cache error') } catch (err) { - console.error(err) t.fail(err.message) } @@ -494,7 +488,6 @@ test('Test SpeculativeNonceTxMiddleware - duplicate tx', async t => { t.equal(cacheErrCount, 1, 'expect to receive only one cache error') } catch (err) { - console.error(err) t.fail(err.message) } @@ -548,7 +541,6 @@ test('Test SpeculativeNonceTxMiddleware - rapid txs', async t => { t.equal(errCount, 0, 'expect to receive no errors') } catch (err) { - console.error(err) t.fail(err.message) } diff --git a/src/tests/e2e/client-test-tx-middleware.ts b/src/tests/e2e/middlewares/client-test-tx-middleware.ts similarity index 91% rename from src/tests/e2e/client-test-tx-middleware.ts rename to src/tests/e2e/middlewares/client-test-tx-middleware.ts index 5e553bde..14fa1a03 100644 --- a/src/tests/e2e/client-test-tx-middleware.ts +++ b/src/tests/e2e/middlewares/client-test-tx-middleware.ts @@ -8,14 +8,14 @@ import { SignedEthTxMiddleware, CryptoUtils, Client -} from '../../index' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { Address, LocalAddress } from '../../address' -import { createDefaultTxMiddleware } from '../../helpers' -import { EthersSigner, getJsonRPCSignerAsync } from '../../solidity-helpers' -import { createTestHttpClient } from '../helpers' -import { AddressMapper, Coin } from '../../contracts' +} from '../../../index' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { Address, LocalAddress } from '../../../address' +import { createDefaultTxMiddleware } from '../../../helpers' +import { EthersSigner, getJsonRPCSignerAsync } from '../../../solidity-helpers' +import { createTestHttpClient } from '../../helpers' +import { AddressMapper, Coin } from '../../../contracts' // import Web3 from 'web3' const Web3 = require('web3') @@ -150,13 +150,13 @@ async function bootstrapTest( return { client, pubKey, privKey, signer, loomProvider, contract, ABI, account } } -test('Test Signed Eth Tx Middleware Type 1', async t => { +test('Test Signed Eth Tx Middleware Type 0', async t => { try { const { client, signer, loomProvider, contract } = await bootstrapTest(createTestHttpClient) // Get address of the account 0 = 0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1 const ethAddress = await signer.getAddress() - const callerChainId = 'eth1' + const callerChainId = 'eth0' // Override the default caller chain ID loomProvider.callerChainId = callerChainId // Ethereum account needs its own middleware @@ -193,7 +193,7 @@ test('Test Signed Eth Tx Middleware Type 1', async t => { t.end() }) -test('Test Signed Eth Tx Middleware Type 2', async t => { +test('Test Signed Eth Tx Middleware Type 1', async t => { try { const { client, signer, pubKey, loomProvider, contract, account } = await bootstrapTest( createTestHttpClient @@ -206,8 +206,9 @@ test('Test Signed Eth Tx Middleware Type 2', async t => { // Set the mapping const ethAddress = await signer.getAddress() + const callerChainId = 'eth1' const from = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) - const to = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(callerChainId, LocalAddress.fromHexString(ethAddress)) // Add mapping if not added yet if (!(await addressMapper.hasMappingAsync(from))) { @@ -223,7 +224,6 @@ test('Test Signed Eth Tx Middleware Type 2', async t => { t.error(err) } - const callerChainId = 'eth' // Override the default caller chain ID loomProvider.callerChainId = callerChainId // Ethereum account needs its own middleware @@ -259,7 +259,7 @@ test('Test Signed Eth Tx Middleware Type 2', async t => { t.end() }) -test('Test Signed Eth Tx Middleware Type 2 with Coin Contract', async t => { +test('Test Signed Eth Tx Middleware Type 1 with Coin Contract', async t => { try { // Create the client const privKey = CryptoUtils.B64ToUint8Array( @@ -280,11 +280,11 @@ test('Test Signed Eth Tx Middleware Type 2 with Coin Contract', async t => { // And get the signer const signer = await getJsonRPCSignerAsync('http://localhost:8545') - + const callerChainId = 'eth1' // Set the mapping const ethAddress = await signer.getAddress() const from = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) - const to = new Address('eth', LocalAddress.fromHexString(ethAddress)) + const to = new Address(callerChainId, LocalAddress.fromHexString(ethAddress)) // Add mapping if not added yet if (!(await addressMapper.hasMappingAsync(from))) { @@ -306,7 +306,7 @@ test('Test Signed Eth Tx Middleware Type 2 with Coin Contract', async t => { // Create Coin wrapper const coin = await Coin.createAsync( client, - new Address('eth', LocalAddress.fromHexString(ethAddress)) + new Address(callerChainId, LocalAddress.fromHexString(ethAddress)) ) const spender = new Address(client.chainId, LocalAddress.fromPublicKey(pubKey)) diff --git a/src/tests/e2e/tron-test-tx-middleware.ts b/src/tests/e2e/middlewares/tron-test-tx-middleware.ts similarity index 92% rename from src/tests/e2e/tron-test-tx-middleware.ts rename to src/tests/e2e/middlewares/tron-test-tx-middleware.ts index f9a96e97..5c97fdde 100644 --- a/src/tests/e2e/tron-test-tx-middleware.ts +++ b/src/tests/e2e/middlewares/tron-test-tx-middleware.ts @@ -1,13 +1,18 @@ import test from 'tape' -import { CachedNonceTxMiddleware, SignedTronTxMiddleware, CryptoUtils, Client } from '../../index' -import { LoomProvider } from '../../loom-provider' -import { deployContract } from '../evm-helpers' -import { Address, LocalAddress } from '../../address' -import { createDefaultTxMiddleware } from '../../helpers' -import { TronWebSigner } from '../../tron-web-signer' -import { createTestHttpClient } from '../helpers' -import { AddressMapper } from '../../contracts' +import { + CachedNonceTxMiddleware, + SignedTronTxMiddleware, + CryptoUtils, + Client +} from '../../../index' +import { LoomProvider } from '../../../loom-provider' +import { deployContract } from '../../evm-helpers' +import { Address, LocalAddress } from '../../../address' +import { createDefaultTxMiddleware } from '../../../helpers' +import { TronWebSigner } from '../../../tron-web-signer' +import { createTestHttpClient } from '../../helpers' +import { AddressMapper } from '../../../contracts' const Web3 = require('web3') const TronWeb = require('tronweb') diff --git a/src/tests/e2e_tests.ts b/src/tests/e2e_tests.ts index f87b081a..54c34673 100644 --- a/src/tests/e2e_tests.ts +++ b/src/tests/e2e_tests.ts @@ -2,37 +2,40 @@ import './e2e/ws-rpc-client-tests' // Loom Provider -import './e2e/loom-provider-tests' -import './e2e/loom-provider-eth-get-logs' -import './e2e/loom-provider-eth-filters' -import './e2e/loom-provider-eth-filters-2' -import './e2e/loom-provider-subscribe' -import './e2e/loom-provider-web3-tests' -import './e2e/loom-provider-web3-middlewares-tests' -import './e2e/loom-provider-web3-child-events' +import './e2e/loom-provider/loom-provider-tests' +import './e2e/loom-provider/loom-provider-web3-tests' +import './e2e/loom-provider/loom-provider-eth-get-logs' +import './e2e/loom-provider/loom-provider-eth-filters' +import './e2e/loom-provider/loom-provider-subscribe' +import './e2e/loom-provider/loom-provider-web3-middlewares-tests' +import './e2e/loom-provider/loom-provider-web3-child-events' +import './e2e/loom-provider/multiple-events-nd-tests' + +// Loom Provider 2 +import './e2e/loom-provider-2/loom-provider-eth-filters' +import './e2e/loom-provider-2/loom-provider-eth-get-logs' +import './e2e/loom-provider-2/loom-provider-subscribe' +import './e2e/loom-provider-2/loom-provider-tests' +import './e2e/loom-provider-2/loom-provider-web3-child-events' +import './e2e/loom-provider-2/loom-provider-web3-tests' +import './e2e/loom-provider-2/multiple-events-nd-tests' // EVM -import './e2e/client-evm-tests' -import './e2e/client-evm-event-tests' -import './e2e/client-evm-event-tests-2' +import './e2e/evm/client-evm-tests' +import './e2e/evm/client-evm-event-tests' +import './e2e/evm/client-evm-event-tests-2' +import './e2e/evm/evm-contract-tests' // Middlewares -import './e2e/client-test-tx-cache' -import './e2e/client-test-tx-middleware' -import './e2e/tron-test-tx-middleware' -import './e2e/binance-test-tx-middleware' - -// Events -import './e2e/multiple-events-nd-tests' +import './e2e/middlewares/client-test-tx-cache' +import './e2e/middlewares/client-test-tx-middleware' +import './e2e/middlewares/tron-test-tx-middleware' +import './e2e/middlewares/binance-test-tx-middleware' // Contracts -import './e2e/coin-tests' -import './e2e/address-mapper-tests' -// TODO: Re-enable once this is updated to DPOSv2 -//import './e2e/dpos-tests' +import './e2e/contracts/coin-tests' +import './e2e/contracts/address-mapper-tests' +import './e2e/contracts/contract-tests' -// Weave Blueprint Contract -import './e2e/contract-tests' - -// Simple Store Contract -import './e2e/evm-contract-tests' +// TODO: Re-enable once this is updated to DPOSv2 +// import './e2e/contracts/dpos-tests' diff --git a/src/tests/evm-helpers.ts b/src/tests/evm-helpers.ts index d58a3e34..ae2a3fe1 100644 --- a/src/tests/evm-helpers.ts +++ b/src/tests/evm-helpers.ts @@ -1,6 +1,8 @@ import { LoomProvider } from '../loom-provider' import { LocalAddress } from '../address' import { CryptoUtils } from '..' +import { LoomProvider2 } from '../loom-provider-2' +import { waitForMillisecondsAsync } from './helpers' export async function deployContract(loomProvider: LoomProvider, contractData: string) { const privKey = loomProvider.accounts.values().next().value @@ -35,3 +37,31 @@ export async function deployContract(loomProvider: LoomProvider, contractData: s return ethGetTransactionReceiptResult.result } + +export async function deployContract2(loomProvider: LoomProvider2, contractData: string) { + const fromAddr = await loomProvider.wallet.getAddress() + + const ethSendTransactionDeployResult = await loomProvider.sendAsync({ + id: 1, + method: 'eth_sendTransaction', + params: [ + { + from: fromAddr, + data: contractData, + gas: '0x0', + gasPrice: '0x0', + value: '0x0' + } + ] + }) + + await waitForMillisecondsAsync(2000) + + const ethGetTransactionReceiptResult = await loomProvider.sendAsync({ + id: 2, + method: 'eth_getTransactionReceipt', + params: [ethSendTransactionDeployResult.result] + }) + + return ethGetTransactionReceiptResult.result +} diff --git a/src/tests/helpers.ts b/src/tests/helpers.ts index 70d437ca..e06394cd 100644 --- a/src/tests/helpers.ts +++ b/src/tests/helpers.ts @@ -5,7 +5,8 @@ export function getTestUrls() { wsWriteUrl: process.env.TEST_LOOM_DAPP_WS_WRITE_URL || 'ws://127.0.0.1:46658/websocket', wsReadUrl: process.env.TEST_LOOM_DAPP_WS_READ_URL || 'ws://127.0.0.1:46658/queryws', httpWriteUrl: process.env.TEST_LOOM_DAPP_HTTP_WRITE_URL || 'http://127.0.0.1:46658/rpc', - httpReadUrl: process.env.TEST_LOOM_DAPP_HTTP_READ_URL || 'http://127.0.0.1:46658/query' + httpReadUrl: process.env.TEST_LOOM_DAPP_HTTP_READ_URL || 'http://127.0.0.1:46658/query', + wsEth: process.env.TEST_LOOM_WS_ETH_URL || 'ws://127.0.0.1:46658/eth' } } diff --git a/tsconfig.json b/tsconfig.json index 0a541d30..da650b37 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -58,6 +58,8 @@ "include": [ "src/index.ts", "src/types/*.d.ts", + "src/types/web3/*.d.ts", + "src/types/web3/eth/*.d.ts", "src/tests/*.ts" ] } \ No newline at end of file