tokenbridge-monitor/contract/abi/abi_test.go

134 lines
4.1 KiB
Go

package abi_test
import (
"bytes"
_ "embed"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
"github.com/omni/tokenbridge-monitor/contract/abi"
"github.com/omni/tokenbridge-monitor/entity"
)
//go:embed test_abi.json
var testJSONABI string
var (
transferTopic = crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)"))
testEventTopic = crypto.Keccak256Hash([]byte("TestEvent(uint256,uint256)"))
testIndexedEventTopic = crypto.Keccak256Hash([]byte("TestIndexedEvent(uint256,uint256)"))
aliceAddr = common.HexToAddress("0x01")
alice = aliceAddr.Hash()
bobAddr = common.HexToAddress("0x02")
bob = bobAddr.Hash()
)
func TestABI_AllEvents(t *testing.T) {
t.Parallel()
testABI := abi.MustReadABI(testJSONABI)
allEvents := testABI.AllEvents()
require.Equal(t, map[string]bool{
"event Transfer(address indexed sender, address indexed receiver, uint256 value)": true,
"event TestEvent(uint256 a, uint256 b)": true,
"event TestIndexedEvent(uint256 indexed a, uint256 indexed b)": true,
}, allEvents)
}
func TestABI_FindMatchingEventABI(t *testing.T) {
t.Parallel()
testABI := abi.MustReadABI(testJSONABI)
event := testABI.FindMatchingEventABI([]common.Hash{transferTopic, alice, bob})
require.NotNil(t, event)
require.Equal(t, "Transfer", event.Name)
event = testABI.FindMatchingEventABI([]common.Hash{transferTopic, alice})
require.Nil(t, event)
event = testABI.FindMatchingEventABI([]common.Hash{transferTopic, alice, bob, alice})
require.Nil(t, event)
event = testABI.FindMatchingEventABI([]common.Hash{testEventTopic})
require.NotNil(t, event)
require.Equal(t, "TestEvent", event.Name)
}
func TestABI_ParseLog(t *testing.T) {
t.Parallel()
testABI := abi.MustReadABI(testJSONABI)
value := big.NewInt(100)
valueHash := common.BigToHash(value)
logData := valueHash.Bytes()
t.Run("should parse valid transfer event", func(t *testing.T) {
t.Parallel()
log := &entity.Log{Topic0: &transferTopic, Topic1: &alice, Topic2: &bob, Data: logData}
event, data, err := testABI.ParseLog(log)
require.NoError(t, err)
require.Equal(t, "event Transfer(address indexed sender, address indexed receiver, uint256 value)", event)
require.Equal(t, map[string]interface{}{
"sender": aliceAddr,
"receiver": bobAddr,
"value": value,
}, data)
})
t.Run("should not parse anonymous event", func(t *testing.T) {
t.Parallel()
log := &entity.Log{Data: logData}
event, data, err := testABI.ParseLog(log)
require.ErrorIs(t, err, abi.ErrInvalidEvent)
require.Empty(t, event)
require.Empty(t, data)
})
t.Run("should skip unknown event", func(t *testing.T) {
t.Parallel()
log := &entity.Log{Topic0: &transferTopic, Data: logData}
event, data, err := testABI.ParseLog(log)
require.NoError(t, err)
require.Empty(t, event)
require.Empty(t, data)
})
t.Run("should decode event without indexed fields", func(t *testing.T) {
t.Parallel()
log := &entity.Log{Topic0: &testEventTopic, Data: bytes.Repeat(logData, 2)}
event, data, err := testABI.ParseLog(log)
require.NoError(t, err)
require.Equal(t, "event TestEvent(uint256 a, uint256 b)", event)
require.Equal(t, map[string]interface{}{
"a": value,
"b": value,
}, data)
})
t.Run("should decode event with only indexed fields", func(t *testing.T) {
t.Parallel()
log := &entity.Log{Topic0: &testIndexedEventTopic, Topic1: &valueHash, Topic2: &valueHash}
event, data, err := testABI.ParseLog(log)
require.NoError(t, err)
require.Equal(t, "event TestIndexedEvent(uint256 indexed a, uint256 indexed b)", event)
require.Equal(t, map[string]interface{}{
"a": value,
"b": value,
}, data)
})
t.Run("should fail to decode event with incompatible ABI", func(t *testing.T) {
t.Parallel()
log := &entity.Log{Topic0: &testEventTopic, Data: logData}
event, data, err := testABI.ParseLog(log)
require.Error(t, err)
require.Contains(t, err.Error(), "length insufficient")
require.Empty(t, event)
require.Empty(t, data)
})
}