Pending transactions, ABI decoding uniswap in golang
This is really a blog post adding more description and explanation of my uniswap-tui repo and I go a bit fast.
Getting pending transactions in golang
…ethclient
has a TODO for pending transaction subscriptions
but we can do some cool golang hacks to grab the right subscription anyway.
client, _ := ethclient.Dial(client_dial)
v := reflect.ValueOf(client).Elem()
f := v.FieldByName("c")
rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem()
concrete_client, _ := rf.Interface().(*rpc.Client)
something := make(chan common.Hash)
concrete_client.EthSubscribe(
context.Background(), something, "newPendingTransactions",
)
for hsh := range something {
txn, is_pending, _ := client.TransactionByHash(context.Background(), hsh)
}
…And now you have the txn and whether its pending (hint: use that parameter)
note this way might break at any moment, aka upstream changes "c"
Decoding ABI methods
Okay - so now we have a pending transaction - but what we usually want are parameters!
Let’s look at pending swaps on uniswap v2
var (
UNISWAP_ROUTER = common.HexToAddress("0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D")
swapExactETHForTokens = [4]byte{0x7f, 0xf3, 0x6a, 0xb5}
// the plain ABI - I just have mine compiled but you grab it from etherscan
router_abi, _ = abi.JSON(strings.NewReader(router.RouterABI))
method_swapExactETHForTokens, _ = router_abi.MethodById(swapExactETHForTokens[:])
)
type t struct {
AmountOutMin *big.Int
Path []common.Address
Deadline *big.Int
To common.Address
}
if is_pending {
_, _ = signer.Sender(txn)
if data := txn.Data(); data != nil {
to := txn.To()
if to != nil {
bytecode, _ := client.CodeAt(
context.Background(), *to, nil,
)
isContract := len(bytecode) > 0
if isContract {
if *to == UNISWAP_ROUTER {
if len(data) < 4 {
continue
}
buf := [4]byte{}
copy(buf[:], data[:4])
switch buf {
case swapExactETHForTokens:
var something t
if err := method_swapExactETHForTokens.Inputs.Unpack(
&something, data[4:],
); err != nil {
log.Fatal(err)
}
cool - so now you have the args that a competitor is using for a swap - happy front running