initial commit phase .
This commit is contained in:
parent
50e2f6d92d
commit
a5f1d08a5e
6 changed files with 4517 additions and 0 deletions
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/target
|
||||||
|
*db*
|
||||||
|
__pycache__/
|
||||||
|
.o
|
||||||
|
.so
|
||||||
|
.exe
|
||||||
|
.pyc
|
||||||
|
.ts
|
||||||
|
*_no.git_*
|
||||||
|
venv/
|
||||||
|
*venv*
|
3902
Cargo.lock
generated
Normal file
3902
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "evmSH"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.70"
|
||||||
|
ethers = "2.0.3"
|
||||||
|
revm = "3.1.1"
|
||||||
|
tokio = "1.27.0"
|
471
bpnpcode.js
Executable file
471
bpnpcode.js
Executable file
|
@ -0,0 +1,471 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
/* note: it can crash a net while running on kernel-space */
|
||||||
|
/*jshint es5:false, asi:true, quotmark:false, eqeqeq:false, forin: false */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (c) 2011-14 Tim Becker, see file LICENSE for details
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provides functionality for bencoding and decoding as use in
|
||||||
|
* bittorrent and described in: http://www.bittorrent.org/beps/bep_0003.html
|
||||||
|
*
|
||||||
|
* Encoding is as follows:
|
||||||
|
*
|
||||||
|
* var benc = require('bncode'),
|
||||||
|
* exmp = {}
|
||||||
|
*
|
||||||
|
* exmp.bla = "blup"
|
||||||
|
* exmp.foo = "bar"
|
||||||
|
* exmp.one = 1
|
||||||
|
* exmp.woah = {}
|
||||||
|
* exmp.woah.arr = []
|
||||||
|
* exmp.woah.arr.push(1)
|
||||||
|
* exmp.woah.arr.push(2)
|
||||||
|
* exmp.woah.arr.push(3)
|
||||||
|
* exmp.str = new Buffer("Buffers work too")
|
||||||
|
*
|
||||||
|
* var bencBuffer = benc.encode(exmp) i
|
||||||
|
*
|
||||||
|
* // d3:bla4:blup3:foo3:bar3:onei1e4:woahd3:arr \
|
||||||
|
* // li1ei2ei3eee3:str16:Buffers work tooe
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Decoding will work in progressively, e.g. if you're receiving partial
|
||||||
|
* bencoded strings on the network:
|
||||||
|
*
|
||||||
|
* var benc = require("bncode"),
|
||||||
|
* buf = null
|
||||||
|
*
|
||||||
|
* decoder = new bncode.decoder()
|
||||||
|
* while (buf = receiveData()) {
|
||||||
|
* decoder.decode(buf)
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* log(decoder.result())
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Or "all in one"
|
||||||
|
*
|
||||||
|
* var benc = require("bncode"),
|
||||||
|
* buf = getBuffer(),
|
||||||
|
* dec = benc.decode(buf)
|
||||||
|
*
|
||||||
|
* log(dec.bla)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* There are some subtleties concerning bencoded strings. These are
|
||||||
|
* decoded as Buffer objects because they are just strings of raw bytes
|
||||||
|
* and as such would wreak havoc with multi byte strings in javascript.
|
||||||
|
*
|
||||||
|
* The exception to this is strings that appear as keys in bencoded
|
||||||
|
* dicts. These are decoded as Javascript Strings, as they should always
|
||||||
|
* be strings of (ascii) characters and if they weren't decoded as JS
|
||||||
|
* Strings, dict's would map to Javascript objects with properties.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.encode = Bencode
|
||||||
|
exports.decoder = Bdecode
|
||||||
|
exports.decode = decode
|
||||||
|
exports.Stream = Stream
|
||||||
|
|
||||||
|
var inherits = require('util').inherits
|
||||||
|
var Transform = require('stream').Transform
|
||||||
|
|
||||||
|
var I = 'i'.charCodeAt(0)
|
||||||
|
var L = 'l'.charCodeAt(0)
|
||||||
|
var E = 'e'.charCodeAt(0)
|
||||||
|
var D = 'd'.charCodeAt(0)
|
||||||
|
var COLON = ':'.charCodeAt(0)
|
||||||
|
var DASH = '-'.charCodeAt(0)
|
||||||
|
|
||||||
|
var STATE_INITIAL = 0
|
||||||
|
var STATE_STATE_STRING_LEN = STATE_INITIAL + 1
|
||||||
|
var STATE_STRING = STATE_STATE_STRING_LEN + 1
|
||||||
|
var STATE_COLON = STATE_STRING + 1
|
||||||
|
var STATE_STATE_INTEGER = STATE_COLON + 1
|
||||||
|
var STATE_INTEGER = STATE_STATE_INTEGER + 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the internal state machine for taking apart bencoded strings,
|
||||||
|
* it's not exposed in the eports. It's constructed with four callbacks
|
||||||
|
* that get fired when:
|
||||||
|
*
|
||||||
|
* cb: a value (string or number) is encountered
|
||||||
|
* cb_list: a begin list element is encountered
|
||||||
|
* cb_dict: a beginning of dictionary is encountered.
|
||||||
|
* cd_end: an end element, wheter dict or list is encountered
|
||||||
|
*
|
||||||
|
* Once constructed, the machine may be fed with buffers containing
|
||||||
|
* partial bencoded string. Call `consistent` to check whether the
|
||||||
|
* current state is consistent, e.g. not smack-dap in the middle of
|
||||||
|
* a string or a number and if the dict, list and end calls balance
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The functionality being so rudimentary requires some more state and
|
||||||
|
* logic in the code executing the machine, for this see Context, below.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function BdecodeSMachine (cb, cb_list, cb_dict, cb_end) {
|
||||||
|
var depth = 0
|
||||||
|
var state = STATE_INITIAL
|
||||||
|
|
||||||
|
this.consistent = function () {
|
||||||
|
return state === STATE_INITIAL && depth === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var strLen = 0
|
||||||
|
var str = ''
|
||||||
|
var _int = 0
|
||||||
|
var neg = false
|
||||||
|
|
||||||
|
this.parse = function (buffer, encoding) {
|
||||||
|
if (typeof buffer === 'string') {
|
||||||
|
buffer = new Buffer(buffer, encoding || 'utf8')
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var pos = 0; pos !== buffer.length; ++pos) {
|
||||||
|
switch (state) {
|
||||||
|
case STATE_INITIAL:
|
||||||
|
switch (buffer[pos]) {
|
||||||
|
case 0x30:
|
||||||
|
case 0x31:
|
||||||
|
case 0x32:
|
||||||
|
case 0x33:
|
||||||
|
case 0x34:
|
||||||
|
case 0x35:
|
||||||
|
case 0x36:
|
||||||
|
case 0x37:
|
||||||
|
case 0x38:
|
||||||
|
case 0x39:
|
||||||
|
state = STATE_STATE_STRING_LEN
|
||||||
|
strLen = 0
|
||||||
|
strLen += buffer[pos] - 0x30
|
||||||
|
break
|
||||||
|
case I:
|
||||||
|
state = STATE_STATE_INTEGER
|
||||||
|
_int = 0
|
||||||
|
neg = false
|
||||||
|
break
|
||||||
|
case L:
|
||||||
|
state = STATE_INITIAL
|
||||||
|
depth += 1
|
||||||
|
cb_list()
|
||||||
|
break
|
||||||
|
case D:
|
||||||
|
state = STATE_INITIAL
|
||||||
|
depth += 1
|
||||||
|
cb_dict()
|
||||||
|
break
|
||||||
|
case E:
|
||||||
|
state = STATE_INITIAL
|
||||||
|
depth -= 1
|
||||||
|
if (depth < 0) {
|
||||||
|
throw new Error('end with no beginning: ' + pos)
|
||||||
|
} else {
|
||||||
|
cb_end()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case STATE_STATE_STRING_LEN:
|
||||||
|
if (integer(buffer[pos])) {
|
||||||
|
strLen *= 10
|
||||||
|
strLen += buffer[pos] - 0x30
|
||||||
|
} else {
|
||||||
|
str = new Buffer(strLen)
|
||||||
|
pos -=1
|
||||||
|
state = STATE_COLON
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case STATE_COLON:
|
||||||
|
if (buffer[pos] !== COLON) {
|
||||||
|
throw new Error('not a colon at: ' + pos.toString(16))
|
||||||
|
}
|
||||||
|
state = STATE_STRING
|
||||||
|
// in case this is a zero length string, there's
|
||||||
|
// no bytes to be collected.
|
||||||
|
if (0 === strLen) {
|
||||||
|
cb(new Buffer(0))
|
||||||
|
state = STATE_INITIAL
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case STATE_STRING:
|
||||||
|
if (0 === strLen) {
|
||||||
|
cb(str)
|
||||||
|
state = STATE_INITIAL
|
||||||
|
} else {
|
||||||
|
//str += String.fromCharCode(buffer[pos]) // not unicode safe..
|
||||||
|
str[str.length-strLen] = buffer[pos]
|
||||||
|
strLen -= 1
|
||||||
|
if (0 === strLen) {
|
||||||
|
cb(str)
|
||||||
|
state = STATE_INITIAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case STATE_STATE_INTEGER:
|
||||||
|
state = STATE_INTEGER
|
||||||
|
if (buffer[pos] === DASH) {
|
||||||
|
neg = true // handle neg and zero within value.
|
||||||
|
break
|
||||||
|
} // else fall through
|
||||||
|
case STATE_INTEGER:
|
||||||
|
if (integer(buffer[pos])) {
|
||||||
|
_int *= 10
|
||||||
|
_int += buffer[pos] - 0x30
|
||||||
|
} else if (buffer[pos] === E) {
|
||||||
|
var ret = neg ? 0 - _int : _int
|
||||||
|
cb(ret)
|
||||||
|
state = STATE_INITIAL
|
||||||
|
} else {
|
||||||
|
throw new Error('not part of int at:'+pos.toString(16))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} // switch state
|
||||||
|
} // for buffer
|
||||||
|
} // function parse
|
||||||
|
|
||||||
|
function integer (value) {
|
||||||
|
// check that value is a number and that
|
||||||
|
// its value is ascii integer.
|
||||||
|
if (typeof value !== 'number') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return between(value, 0x30, 0x39)
|
||||||
|
}
|
||||||
|
function between (val, min, max) {
|
||||||
|
return (min <= val && val <= max)
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end BdecodeSMachine
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The exported decode functionality.
|
||||||
|
*/
|
||||||
|
function Bdecode () {
|
||||||
|
// markers
|
||||||
|
var DICTIONARY_START = {}
|
||||||
|
var LIST_START = {}
|
||||||
|
|
||||||
|
var Context = function () {
|
||||||
|
var self = this
|
||||||
|
var stack = []
|
||||||
|
|
||||||
|
this.cb = function (o) {
|
||||||
|
stack.push(o)
|
||||||
|
}
|
||||||
|
this.cb_list = function () {
|
||||||
|
self.cb(LIST_START)
|
||||||
|
}
|
||||||
|
this.cb_dict = function () {
|
||||||
|
self.cb(DICTIONARY_START)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cb_end = function () {
|
||||||
|
|
||||||
|
// unwind the stack until either a DICTIONARY_START or LIST_START is
|
||||||
|
// found, create arr or hash, stick unwound stack on, push arr or hash
|
||||||
|
// back onto stack
|
||||||
|
|
||||||
|
var obj = null
|
||||||
|
var tmp_stack = []
|
||||||
|
|
||||||
|
while ((obj = stack.pop()) !== undefined) {
|
||||||
|
if (LIST_START === obj) {
|
||||||
|
var obj2 = null
|
||||||
|
var list = []
|
||||||
|
while((obj2 = tmp_stack.pop()) !== undefined) {
|
||||||
|
list.push(obj2)
|
||||||
|
}
|
||||||
|
self.cb(list)
|
||||||
|
break
|
||||||
|
} else if (DICTIONARY_START === obj) {
|
||||||
|
var key = null
|
||||||
|
var val = null
|
||||||
|
var dic = {}
|
||||||
|
while ((key = tmp_stack.pop()) !== undefined && (val = tmp_stack.pop()) !== undefined) {
|
||||||
|
dic[key.toString()] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key !== undefined && dic[key] === undefined) {
|
||||||
|
throw new Error('uneven number of keys and values A')
|
||||||
|
}
|
||||||
|
self.cb(dic)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
tmp_stack.push(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tmp_stack.length > 0) {
|
||||||
|
// could this case even occur?
|
||||||
|
throw new Error('uneven number of keys and values B')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.result = function () {
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var self = this
|
||||||
|
var ctx = new Context()
|
||||||
|
var smachine = new BdecodeSMachine(ctx.cb, ctx.cb_list, ctx.cb_dict, ctx.cb_end)
|
||||||
|
|
||||||
|
this.result = function () {
|
||||||
|
if (!smachine.consistent()) {
|
||||||
|
throw new Error('not in consistent state. More bytes coming?')
|
||||||
|
}
|
||||||
|
return ctx.result()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.decode = function (buf, encoding) {
|
||||||
|
smachine.parse(buf, encoding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Bencode (obj) {
|
||||||
|
var self = this
|
||||||
|
var to_encode = obj
|
||||||
|
var buffer = null
|
||||||
|
|
||||||
|
switch (typeof obj) {
|
||||||
|
case 'string':
|
||||||
|
return encodeString(obj)
|
||||||
|
case 'number':
|
||||||
|
return encodeNumber(obj)
|
||||||
|
case 'object':
|
||||||
|
if (obj instanceof Array) {
|
||||||
|
return encodeList(obj)
|
||||||
|
} else if (Buffer.isBuffer(obj)) {
|
||||||
|
return encodeBuffer(obj)
|
||||||
|
} else {
|
||||||
|
// assume it's a hash
|
||||||
|
return encodeDict(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeString (obj) {
|
||||||
|
var blen = Buffer.byteLength(obj)
|
||||||
|
var len = blen.toString(10)
|
||||||
|
var buf = new Buffer(len.length + 1 + blen)
|
||||||
|
|
||||||
|
buf.write(len, 0, 'ascii')
|
||||||
|
buf.write(':', len.length, 'ascii')
|
||||||
|
buf.write(obj, len.length + 1, 'utf8')
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeNumber (num) {
|
||||||
|
var n = num.toString(10)
|
||||||
|
var buf = new Buffer(n.length + 2)
|
||||||
|
|
||||||
|
buf.write('i', 0)
|
||||||
|
buf.write(n, 1)
|
||||||
|
buf.write('e', n.length + 1)
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeDict (obj) {
|
||||||
|
var func = function (obj, pos) {
|
||||||
|
var keys = Object.keys(obj).sort()
|
||||||
|
keys.forEach(function (key) {
|
||||||
|
var val = new Bencode(obj[key])
|
||||||
|
key = new Bencode(key)
|
||||||
|
|
||||||
|
ensure(key.length + val.length, pos)
|
||||||
|
key.copy(buffer, pos, 0)
|
||||||
|
pos += key.length
|
||||||
|
val.copy(buffer, pos, 0)
|
||||||
|
pos += val.length
|
||||||
|
})
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
return assemble(obj, 'd', func)
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeList (obj) {
|
||||||
|
var func = function(obj, pos) {
|
||||||
|
obj.forEach(function (o) {
|
||||||
|
var elem = new Bencode(o)
|
||||||
|
|
||||||
|
ensure(elem.length, pos)
|
||||||
|
elem.copy(buffer, pos, 0)
|
||||||
|
pos += elem.length
|
||||||
|
})
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
return assemble(obj, 'l', func)
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodeBuffer (obj) {
|
||||||
|
var len = obj.length.toString(10)
|
||||||
|
var buf = new Buffer(len.length + 1 + obj.length)
|
||||||
|
|
||||||
|
buf.write(len, 0, 'ascii')
|
||||||
|
buf.write(':', len.length, 'ascii')
|
||||||
|
obj.copy(buf, len.length + 1, 0)
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
function assemble (obj, prefix, func) {
|
||||||
|
var pos = 0
|
||||||
|
|
||||||
|
ensure(1024, 0)
|
||||||
|
buffer.write(prefix, pos++)
|
||||||
|
|
||||||
|
pos = func(obj, pos)
|
||||||
|
ensure(1, pos)
|
||||||
|
|
||||||
|
buffer.write('e', pos++)
|
||||||
|
return buffer.slice(0, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensure (num, pos) {
|
||||||
|
if (!buffer) {
|
||||||
|
buffer = new Buffer(num)
|
||||||
|
} else {
|
||||||
|
if (buffer.length > num + pos + 1) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
var buf2 = new Buffer(buffer.length + num)
|
||||||
|
buffer.copy(buf2, 0, 0)
|
||||||
|
buffer = buf2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function decode (buffer, encoding) {
|
||||||
|
var decoder = new Bdecode()
|
||||||
|
|
||||||
|
decoder.decode(buffer, encoding)
|
||||||
|
return decoder.result()[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
function Stream (options) {
|
||||||
|
options = options || {}
|
||||||
|
options.objectMode = true
|
||||||
|
Transform.call(this, options)
|
||||||
|
this._decoder = new Bdecode()
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(Stream, Transform)
|
||||||
|
|
||||||
|
Stream.prototype._transform = function (chunk, encoding, callback) {
|
||||||
|
try {
|
||||||
|
this._decoder.decode(chunk, encoding)
|
||||||
|
callback(null)
|
||||||
|
} catch(err) {
|
||||||
|
callback(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.prototype._flush = function (callback) {
|
||||||
|
this.push(this._decoder.result()[0])
|
||||||
|
callback(null)
|
||||||
|
}
|
9
src/main.rs
Normal file
9
src/main.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
use waddaFork::tait;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<()> {
|
||||||
|
// create ethers client and wrap it in Arc<M>
|
||||||
|
// let client = Arc::new(nick.local.CLIENT);
|
||||||
|
await tait().?;
|
||||||
|
println!("Hello, world!");
|
||||||
|
}
|
112
src/waddaFork.rs
Normal file
112
src/waddaFork.rs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
use std::{str::FromStr, sync::Arc};
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
use bytes::Bytes;
|
||||||
|
use ethers::{
|
||||||
|
abi::parse_abi,
|
||||||
|
prelude::BaseContract,
|
||||||
|
providers::{Http, Provider},
|
||||||
|
};
|
||||||
|
use revm::{
|
||||||
|
db::{CacheDB, EmptyDB, EthersDB},
|
||||||
|
primitives::{ExecutionResult, Output, TransactTo, B160, U256 as rU256},
|
||||||
|
Database, EVM,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn tait() -> Result<()> {
|
||||||
|
// create ethers client and wrap it in Arc<M>
|
||||||
|
let client = Provider::<Http>::try_from(
|
||||||
|
"https://mainnet.infura.io/v3/c60b0bb42f8a4c6481ecd229eddaca27",
|
||||||
|
)?;
|
||||||
|
let client = Arc::new(client);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- //
|
||||||
|
// Storage slots of UniV2Pair contract //
|
||||||
|
// =========================================================== //
|
||||||
|
// storage[5] = factory: address //
|
||||||
|
// storage[6] = token0: address //
|
||||||
|
// storage[7] = token1: address //
|
||||||
|
// storage[8] = (res0, res1, ts): (uint112, uint112, uint32) //
|
||||||
|
// storage[9] = price0CumulativeLast: uint256 //
|
||||||
|
// storage[10] = price1CumulativeLast: uint256 //
|
||||||
|
// storage[11] = kLast: uint256 //
|
||||||
|
// =========================================================== //
|
||||||
|
|
||||||
|
// choose slot of storage that you would like to transact with
|
||||||
|
let slot = rU256::from(8);
|
||||||
|
|
||||||
|
// ETH/USDT pair on Uniswap V2
|
||||||
|
let pool_address = B160::from_str("0x252ea274ff957494274057ed94844ffd7184e21f")?;
|
||||||
|
|
||||||
|
// generate abi for the calldata from the human readable interface
|
||||||
|
let abi = BaseContract::from(
|
||||||
|
parse_abi(&[
|
||||||
|
"function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast)",
|
||||||
|
])?
|
||||||
|
);
|
||||||
|
|
||||||
|
// encode abi into Bytes
|
||||||
|
let encoded = abi.encode("getReserves", ())?;
|
||||||
|
|
||||||
|
// initialize new EthersDB
|
||||||
|
let mut ethersdb = EthersDB::new(Arc::clone(&client), None).unwrap();
|
||||||
|
|
||||||
|
// query basic properties of an account incl bytecode
|
||||||
|
let acc_info = ethersdb.basic(pool_address).unwrap().unwrap();
|
||||||
|
|
||||||
|
// query value of storage slot at account address
|
||||||
|
let value = ethersdb.storage(pool_address, slot).unwrap();
|
||||||
|
|
||||||
|
// initialise empty in-memory-db
|
||||||
|
let mut cache_db = CacheDB::new(EmptyDB::default());
|
||||||
|
|
||||||
|
// insert basic account info which was generated via Web3DB with the corresponding address
|
||||||
|
cache_db.insert_account_info(pool_address, acc_info);
|
||||||
|
|
||||||
|
// insert our pre-loaded storage slot to the corresponding contract key (address) in the DB
|
||||||
|
cache_db
|
||||||
|
.insert_account_storage(pool_address, slot, value)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// initialise an empty (default) EVM
|
||||||
|
let mut evm = EVM::new();
|
||||||
|
|
||||||
|
// insert pre-built database from above
|
||||||
|
evm.database(cache_db);
|
||||||
|
|
||||||
|
// fill in missing bits of env struc
|
||||||
|
// change that to whatever caller you want to be
|
||||||
|
evm.env.tx.caller = B160::from_str("0x0000000000000000000000000000000000000000")?;
|
||||||
|
// account you want to transact with
|
||||||
|
evm.env.tx.transact_to = TransactTo::Call(pool_address);
|
||||||
|
// calldata formed via abigen
|
||||||
|
evm.env.tx.data = Bytes::from(hex::decode(hex::encode(&encoded))?);
|
||||||
|
// transaction value in wei
|
||||||
|
evm.env.tx.value = rU256::try_from(0)?;
|
||||||
|
|
||||||
|
// execute transaction without writing to the DB
|
||||||
|
let ref_tx = evm.transact_ref().unwrap();
|
||||||
|
// select ExecutionResult struct
|
||||||
|
let result = ref_tx.result;
|
||||||
|
|
||||||
|
// unpack output call enum into raw bytes
|
||||||
|
let value = match result {
|
||||||
|
ExecutionResult::Success { output, .. } => match output {
|
||||||
|
Output::Call(value) => Some(value),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// decode bytes to reserves + ts via ethers-rs's abi decode
|
||||||
|
let (reserve0, reserve1, ts): (u128, u128, u32) =
|
||||||
|
abi.decode_output("getReserves", value.unwrap())?;
|
||||||
|
|
||||||
|
// Print emulated getReserves() call output
|
||||||
|
println!("Reserve0: {:#?}", reserve0);
|
||||||
|
println!("Reserve1: {:#?}", reserve1);
|
||||||
|
println!("Timestamp: {:#?}", ts);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue