|
| 1 | +import { assert } from 'chai'; |
| 2 | +import {BigNumber, BigNumberish, providers, utils} from 'ethers'; |
| 3 | +import { BlockWithTransactions} from '@ethersproject/abstract-provider'; |
| 4 | +import {Simulator} from './simulator'; |
| 5 | + |
| 6 | +async function noBlockTag(blockTag: any) { |
| 7 | + if (await blockTag) { |
| 8 | + throw new Error('🟥 Not implemented: blockTag'); |
| 9 | + } |
| 10 | +} |
| 11 | + |
| 12 | +export class DGethProvider extends providers.Provider { |
| 13 | + sim: Simulator |
| 14 | + |
| 15 | + constructor() { |
| 16 | + super(); |
| 17 | + this.sim = new Simulator(); |
| 18 | + } |
| 19 | + |
| 20 | + async call( |
| 21 | + transaction: utils.Deferrable<providers.TransactionRequest>, |
| 22 | + blockTag?: providers.BlockTag | Promise<providers.BlockTag> |
| 23 | + ): Promise<string> { |
| 24 | + await noBlockTag(blockTag); |
| 25 | + const tx = await utils.resolveProperties(transaction) |
| 26 | + |
| 27 | + assert(tx.to, 'transaction.to is required'); |
| 28 | + return this.sim.call({ |
| 29 | + from: tx.from, |
| 30 | + to: tx.to!, |
| 31 | + gas: tx.gasLimit ? BigNumber.from(tx.gasLimit).toNumber() : undefined, |
| 32 | + gasPrice: tx.gasPrice ? BigNumber.from(tx.gasPrice).toHexString() : undefined, |
| 33 | + // gasFeeCap: BigNumber.from(tx.gasFeeCap).toHexString(), |
| 34 | + // gasTipCap: BigNumber.from(tx.gasTipCap).toHexString(), |
| 35 | + value: tx.value ? BigNumber.from(tx.value).toHexString() : undefined, |
| 36 | + data: tx.data ? BigNumber.from(tx.data).toHexString() : undefined, |
| 37 | + })!; |
| 38 | + } |
| 39 | + |
| 40 | + emit(eventName: providers.EventType, ...args: Array<any>): boolean { |
| 41 | + throw new Error('🟥 Not implemented'); |
| 42 | + } |
| 43 | + |
| 44 | + estimateGas(transaction: utils.Deferrable<providers.TransactionRequest>): Promise<BigNumber> { |
| 45 | + throw new Error('🟥 Not implemented'); |
| 46 | + } |
| 47 | + |
| 48 | + async getBalance( |
| 49 | + addressOrName: string | Promise<string>, |
| 50 | + blockTag?: providers.BlockTag | Promise<providers.BlockTag> |
| 51 | + ): Promise<BigNumber> { |
| 52 | + await noBlockTag(blockTag); |
| 53 | + const address = await addressOrName; |
| 54 | + if (!utils.isAddress(address)) { |
| 55 | + throw new Error('🟥 Not implemented: ENS'); |
| 56 | + } |
| 57 | + return BigNumber.from(this.sim.getBalance(address)); |
| 58 | + } |
| 59 | + |
| 60 | + async getBlock(blockHashOrBlockTag: providers.BlockTag | string | Promise<providers.BlockTag | string>): Promise<providers.Block> { |
| 61 | + const block = this.sim.getBlock((await blockHashOrBlockTag).toString()) |
| 62 | + const difficulty = BigNumber.from(block.difficulty) |
| 63 | + return { |
| 64 | + transactions: [], // TODO |
| 65 | + difficulty: difficulty.toNumber(), |
| 66 | + _difficulty: difficulty, |
| 67 | + extraData: '', |
| 68 | + gasLimit: BigNumber.from(block.gasLimit), |
| 69 | + gasUsed: BigNumber.from(block.gasUsed), |
| 70 | + hash: block.hash, |
| 71 | + miner: block.miner, |
| 72 | + nonce: block.nonce, |
| 73 | + number: BigNumber.from(block.number).toNumber(), |
| 74 | + parentHash: block.parentHash, |
| 75 | + timestamp: BigNumber.from(block.timestamp).toNumber(), |
| 76 | + baseFeePerGas: BigNumber.from(block.baseFeePerGas) |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + getBlockNumber(): Promise<number> { |
| 81 | + return Promise.resolve(Number.parseInt(this.sim.getBlockNumber())); |
| 82 | + } |
| 83 | + |
| 84 | + getBlockWithTransactions( |
| 85 | + blockHashOrBlockTag: providers.BlockTag | string | Promise<providers.BlockTag | string> |
| 86 | + ): Promise<BlockWithTransactions> { |
| 87 | + throw new Error('🟥 Not implemented'); |
| 88 | + } |
| 89 | + |
| 90 | + async getCode(addressOrName: string | Promise<string>, blockTag?: providers.BlockTag | Promise<providers.BlockTag>): Promise<string> { |
| 91 | + return this.sim.getCode(await addressOrName); |
| 92 | + } |
| 93 | + |
| 94 | + async getGasPrice(): Promise<BigNumber> { |
| 95 | + return BigNumber.from(8000000); |
| 96 | + } |
| 97 | + |
| 98 | + async getLogs(filter: providers.Filter): Promise<providers.Log[]> { |
| 99 | + throw new Error('🟥 Not implemented'); |
| 100 | + } |
| 101 | + |
| 102 | + getNetwork(): Promise<providers.Network> { |
| 103 | + const network: providers.Network = { |
| 104 | + name: 'undefined', |
| 105 | + chainId: Number.parseInt(this.sim.getChainID()) |
| 106 | + }; |
| 107 | + return Promise.resolve(network); |
| 108 | + } |
| 109 | + |
| 110 | + getStorageAt( |
| 111 | + addressOrName: string | Promise<string>, |
| 112 | + position: BigNumberish | Promise<BigNumberish>, |
| 113 | + blockTag?: providers.BlockTag | Promise<providers.BlockTag> |
| 114 | + ): Promise<string> { |
| 115 | + throw new Error('🟥 Not implemented'); |
| 116 | + } |
| 117 | + |
| 118 | + async getTransaction(transactionHash: string): Promise<providers.TransactionResponse> { |
| 119 | + const {Tx} = this.sim.getTransaction(transactionHash); |
| 120 | + return { |
| 121 | + hash: Tx.hash, |
| 122 | + to: Tx.to, |
| 123 | + nonce: Number.parseInt(Tx.nonce, 16), |
| 124 | + |
| 125 | + gasLimit: BigNumber.from(Tx.gas), |
| 126 | + // TODO |
| 127 | + // gasPrice: BigNumber.from(Tx.gasPrice), |
| 128 | + |
| 129 | + data: Tx.input, |
| 130 | + value: BigNumber.from(Tx.value), |
| 131 | + chainId: Number.parseInt(this.sim.getChainID(), 16), |
| 132 | + |
| 133 | + // TODO |
| 134 | + // r: Tx.r, |
| 135 | + // s: Tx.s, |
| 136 | + // v: Tx.v, |
| 137 | + |
| 138 | + confirmations: 0, |
| 139 | + from: '0x', |
| 140 | + wait: () => { throw new Error('🟥 Not implemented'); } |
| 141 | + }; |
| 142 | + } |
| 143 | + |
| 144 | + async getTransactionCount( |
| 145 | + addressOrName: string | Promise<string>, |
| 146 | + blockTag?: providers.BlockTag | Promise<providers.BlockTag> |
| 147 | + ): Promise<number> { |
| 148 | + return this.sim.getTransactionCount(await addressOrName); |
| 149 | + } |
| 150 | + |
| 151 | + getTransactionReceipt(transactionHash: string): Promise<providers.TransactionReceipt> { |
| 152 | + throw new Error('🟥 Not implemented'); |
| 153 | + } |
| 154 | + |
| 155 | + listenerCount(eventName?: providers.EventType): number { |
| 156 | + throw new Error('🟥 Not implemented'); |
| 157 | + } |
| 158 | + |
| 159 | + listeners(eventName?: providers.EventType): Array<providers.Listener> { |
| 160 | + throw new Error('🟥 Not implemented'); |
| 161 | + } |
| 162 | + |
| 163 | + lookupAddress(address: string | Promise<string>): Promise<string> { |
| 164 | + throw new Error('🟥 Not implemented'); |
| 165 | + } |
| 166 | + |
| 167 | + off(eventName: providers.EventType, listener?: providers.Listener): providers.Provider { |
| 168 | + throw new Error('🟥 Not implemented'); |
| 169 | + } |
| 170 | + |
| 171 | + on(eventName: providers.EventType, listener: providers.Listener): providers.Provider { |
| 172 | + throw new Error('🟥 Not implemented'); |
| 173 | + } |
| 174 | + |
| 175 | + once(eventName: providers.EventType, listener: providers.Listener): providers.Provider; |
| 176 | + once(eventName: 'block', handler: () => void): void; |
| 177 | + once(eventName: providers.EventType | 'block', listener: providers.Listener | (() => void)): providers.Provider | void { |
| 178 | + throw new Error('🟥 Not implemented'); |
| 179 | + } |
| 180 | + |
| 181 | + removeAllListeners(eventName?: providers.EventType): providers.Provider { |
| 182 | + throw new Error('🟥 Not implemented'); |
| 183 | + } |
| 184 | + |
| 185 | + async resolveName(name: string | Promise<string>): Promise<string> { |
| 186 | + return name; |
| 187 | + } |
| 188 | + |
| 189 | + async sendTransaction(signedTransaction: string | Promise<string>): Promise<providers.TransactionResponse> { |
| 190 | + const data = await signedTransaction; |
| 191 | + const receipt = this.sim.sendTransaction(data) |
| 192 | + |
| 193 | + // https://docs.ethers.io/v5/api/providers/types/#providers-TransactionReceipt |
| 194 | + const ethersReceipt: providers.TransactionReceipt & providers.TransactionResponse = { |
| 195 | + |
| 196 | + to: receipt.to === '' ? null as any : receipt.to, |
| 197 | + from: receipt.from, |
| 198 | + nonce: 0, // TODO |
| 199 | + |
| 200 | + gasLimit: BigNumber.from(0), // TODO |
| 201 | + gasPrice: BigNumber.from(0), // TODO |
| 202 | + |
| 203 | + data: '0x', // TODO |
| 204 | + value: BigNumber.from(0), // TODO |
| 205 | + chainId: 1337, // TODO |
| 206 | + |
| 207 | + // r?: string, |
| 208 | + // s?: string, |
| 209 | + // v?: number, |
| 210 | + |
| 211 | + // Typed-Transaction features |
| 212 | + // type?: number | null, |
| 213 | + |
| 214 | + // EIP-2930; Type 1 & EIP-1559; Type 2 |
| 215 | + // accessList?: AccessList, |
| 216 | + |
| 217 | + // EIP-1559; Type 2 |
| 218 | + // maxPriorityFeePerGas?: BigNumber, |
| 219 | + // maxFeePerGas?: BigNumber, |
| 220 | + hash: receipt.txHash, |
| 221 | + |
| 222 | + // Only if a transaction has been mined |
| 223 | + blockNumber: BigNumber.from(receipt.blockNumber).toNumber(), |
| 224 | + blockHash: receipt.blockHash, |
| 225 | + // timestamp?: number, |
| 226 | + |
| 227 | + confirmations: 1, |
| 228 | + |
| 229 | + // 🟥 Not optional (as it is in Transaction) |
| 230 | + |
| 231 | + // The raw transaction |
| 232 | + raw: data, |
| 233 | + |
| 234 | + // This function waits until the transaction has been mined |
| 235 | + wait: async (confirmations?: number) => ethersReceipt, |
| 236 | + |
| 237 | + |
| 238 | + contractAddress: receipt.contractAddress, |
| 239 | + transactionIndex: receipt.transactionIndex, |
| 240 | + // root?: string, |
| 241 | + gasUsed: BigNumber.from(receipt.gasUsed), |
| 242 | + logsBloom: 'TODO', |
| 243 | + transactionHash: receipt.txHash, |
| 244 | + logs: [], // TODO |
| 245 | + cumulativeGasUsed: BigNumber.from(receipt.cumulativeGasUsed), |
| 246 | + effectiveGasPrice: BigNumber.from(10000), // TODO |
| 247 | + byzantium: true, |
| 248 | + type: receipt.type, |
| 249 | + status: receipt.status, |
| 250 | + }; |
| 251 | + |
| 252 | + return ethersReceipt; |
| 253 | + } |
| 254 | + |
| 255 | + waitForTransaction(transactionHash: string, confirmations?: number, timeout?: number): Promise<providers.TransactionReceipt> { |
| 256 | + throw new Error('🟥 Not implemented'); |
| 257 | + } |
| 258 | +} |
0 commit comments