ABI tests
This commit is contained in:
parent
c2548e248c
commit
1e5fb85fae
|
@ -1,60 +1,91 @@
|
||||||
package abi
|
package abi
|
||||||
|
|
||||||
//nolint:golint
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
gethabi "github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
|
"github.com/poanetwork/tokenbridge-monitor/entity"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed amb.json
|
type ABI struct {
|
||||||
var arbitraryMessageJSONABI string
|
gethabi.ABI
|
||||||
|
}
|
||||||
|
|
||||||
//go:embed erc_to_native.json
|
type Event struct {
|
||||||
var ercToNativeJSONABI string
|
gethabi.Event
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var ErrInvalidEvent = errors.New("invalid event")
|
||||||
ArbitraryMessageABI = MustReadABI(arbitraryMessageJSONABI)
|
|
||||||
ErcToNativeABI = MustReadABI(ercToNativeJSONABI)
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
func MustReadABI(rawJSON string) ABI {
|
||||||
UserRequestForSignature = "event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData)"
|
res, err := gethabi.JSON(strings.NewReader(rawJSON))
|
||||||
LegacyUserRequestForSignature = "event UserRequestForSignature(bytes encodedData)"
|
|
||||||
UserRequestForAffirmation = "event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData)"
|
|
||||||
LegacyUserRequestForAffirmation = "event UserRequestForAffirmation(bytes encodedData)"
|
|
||||||
UserRequestForInformation = "event UserRequestForInformation(bytes32 indexed messageId, bytes32 indexed requestSelector, address indexed sender, bytes data)"
|
|
||||||
SignedForUserRequest = "event SignedForUserRequest(address indexed signer, bytes32 messageHash)"
|
|
||||||
SignedForAffirmation = "event SignedForAffirmation(address indexed signer, bytes32 messageHash)"
|
|
||||||
SignedForInformation = "event SignedForInformation(address indexed signer, bytes32 indexed messageId)"
|
|
||||||
CollectedSignatures = "event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash, uint256 NumberOfCollectedSignatures)"
|
|
||||||
AffirmationCompleted = "event AffirmationCompleted(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status)"
|
|
||||||
LegacyAffirmationCompleted = "event AffirmationCompleted(address sender, address executor, bytes32 messageId, bool status)"
|
|
||||||
RelayedMessage = "event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status)"
|
|
||||||
LegacyRelayedMessage = "event RelayedMessage(address sender, address executor, bytes32 messageId, bool status)"
|
|
||||||
InformationRetrieved = "event InformationRetrieved(bytes32 indexed messageId, bool status, bool callbackStatus)"
|
|
||||||
|
|
||||||
ErcToNativeUserRequestForSignature = "event UserRequestForSignature(address recipient, uint256 value)"
|
|
||||||
ErcToNativeTransfer = "event Transfer(address indexed from, address indexed to, uint256 value)"
|
|
||||||
ErcToNativeRelayedMessage = "event RelayedMessage(address recipient, uint256 value, bytes32 transactionHash)"
|
|
||||||
ErcToNativeUserRequestForAffirmation = "event UserRequestForAffirmation(address recipient, uint256 value)"
|
|
||||||
ErcToNativeAffirmationCompleted = "event AffirmationCompleted(address recipient, uint256 value, bytes32 transactionHash)"
|
|
||||||
ErcToNativeSignedForAffirmation = "event SignedForAffirmation(address indexed signer, bytes32 transactionHash)"
|
|
||||||
|
|
||||||
ValidatorAdded = "event ValidatorAdded(address indexed validator)"
|
|
||||||
ValidatorRemoved = "event ValidatorRemoved(address indexed validator)"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErcToNativeTransferEventSignature = ErcToNativeABI.Events["Transfer"].ID
|
|
||||||
ErcToNativeUserRequestForAffirmationEventSignature = ErcToNativeABI.Events["UserRequestForAffirmation"].ID
|
|
||||||
)
|
|
||||||
|
|
||||||
func MustReadABI(rawJSON string) abi.ABI {
|
|
||||||
res, err := abi.JSON(strings.NewReader(rawJSON))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return res
|
return ABI{res}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (abi *ABI) AllEvents() map[string]bool {
|
||||||
|
events := make(map[string]bool, len(abi.Events))
|
||||||
|
for _, event := range abi.Events {
|
||||||
|
events[event.String()] = true
|
||||||
|
}
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
func (abi *ABI) FindMatchingEventABI(topics []common.Hash) *Event {
|
||||||
|
for _, e := range abi.Events {
|
||||||
|
if e.ID == topics[0] {
|
||||||
|
indexed := Indexed(e.Inputs)
|
||||||
|
if len(indexed) == len(topics)-1 {
|
||||||
|
return &Event{e}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (abi *ABI) ParseLog(log *entity.Log) (string, map[string]interface{}, error) {
|
||||||
|
topics := log.Topics()
|
||||||
|
if len(topics) == 0 {
|
||||||
|
return "", nil, fmt.Errorf("cannot process event without topics: %w", ErrInvalidEvent)
|
||||||
|
}
|
||||||
|
event := abi.FindMatchingEventABI(topics)
|
||||||
|
if event == nil {
|
||||||
|
return "", nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := event.DecodeLogData(topics, log.Data)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("can't decode event log data: %w", err)
|
||||||
|
}
|
||||||
|
return event.String(), res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (event *Event) DecodeLogData(topics []common.Hash, data []byte) (map[string]interface{}, error) {
|
||||||
|
indexed := Indexed(event.Inputs)
|
||||||
|
values := make(map[string]interface{})
|
||||||
|
if len(indexed) < len(event.Inputs) {
|
||||||
|
if err := event.Inputs.UnpackIntoMap(values, data); err != nil {
|
||||||
|
return nil, fmt.Errorf("can't unpack data: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := gethabi.ParseTopicsIntoMap(values, indexed, topics[1:]); err != nil {
|
||||||
|
return nil, fmt.Errorf("can't unpack topics: %w", err)
|
||||||
|
}
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Indexed(args gethabi.Arguments) gethabi.Arguments {
|
||||||
|
var indexed gethabi.Arguments
|
||||||
|
for _, arg := range args {
|
||||||
|
if arg.Indexed {
|
||||||
|
indexed = append(indexed, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return indexed
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
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/poanetwork/tokenbridge-monitor/contract/abi"
|
||||||
|
"github.com/poanetwork/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)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"constant": true,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "testMethod",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"payable": false,
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "sender",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "receiver",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Transfer",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "a",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"name": "b",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "TestEvent",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "a",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"name": "b",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "TestIndexedEvent",
|
||||||
|
"type": "event"
|
||||||
|
}
|
||||||
|
]
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/poanetwork/tokenbridge-monitor/config"
|
"github.com/poanetwork/tokenbridge-monitor/config"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/contract/abi"
|
"github.com/poanetwork/tokenbridge-monitor/contract/abi"
|
||||||
|
"github.com/poanetwork/tokenbridge-monitor/contract/bridgeabi"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,16 +17,14 @@ type BridgeContract struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBridgeContract(client ethclient.Client, addr common.Address, mode config.BridgeMode) *BridgeContract {
|
func NewBridgeContract(client ethclient.Client, addr common.Address, mode config.BridgeMode) *BridgeContract {
|
||||||
var contract *Contract
|
return &BridgeContract{NewContract(client, addr, getBridgeABI(mode))}
|
||||||
switch mode {
|
}
|
||||||
case config.BridgeModeArbitraryMessage:
|
|
||||||
contract = NewContract(client, addr, abi.ArbitraryMessageABI)
|
func getBridgeABI(mode config.BridgeMode) abi.ABI {
|
||||||
case config.BridgeModeErcToNative:
|
if mode == config.BridgeModeErcToNative {
|
||||||
contract = NewContract(client, addr, abi.ErcToNativeABI)
|
return bridgeabi.ErcToNativeABI
|
||||||
default:
|
|
||||||
contract = NewContract(client, addr, abi.ArbitraryMessageABI)
|
|
||||||
}
|
}
|
||||||
return &BridgeContract{contract}
|
return bridgeabi.ArbitraryMessageABI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *BridgeContract) ValidatorContractAddress(ctx context.Context) (common.Address, error) {
|
func (c *BridgeContract) ValidatorContractAddress(ctx context.Context) (common.Address, error) {
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package bridgeabi
|
||||||
|
|
||||||
|
//nolint:golint
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/poanetwork/tokenbridge-monitor/contract/abi"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed amb.json
|
||||||
|
var arbitraryMessageJSONABI string
|
||||||
|
|
||||||
|
//go:embed erc_to_native.json
|
||||||
|
var ercToNativeJSONABI string
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserRequestForSignature = "event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData)"
|
||||||
|
LegacyUserRequestForSignature = "event UserRequestForSignature(bytes encodedData)"
|
||||||
|
UserRequestForAffirmation = "event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData)"
|
||||||
|
LegacyUserRequestForAffirmation = "event UserRequestForAffirmation(bytes encodedData)"
|
||||||
|
UserRequestForInformation = "event UserRequestForInformation(bytes32 indexed messageId, bytes32 indexed requestSelector, address indexed sender, bytes data)"
|
||||||
|
SignedForUserRequest = "event SignedForUserRequest(address indexed signer, bytes32 messageHash)"
|
||||||
|
SignedForAffirmation = "event SignedForAffirmation(address indexed signer, bytes32 messageHash)"
|
||||||
|
SignedForInformation = "event SignedForInformation(address indexed signer, bytes32 indexed messageId)"
|
||||||
|
CollectedSignatures = "event CollectedSignatures(address authorityResponsibleForRelay, bytes32 messageHash, uint256 NumberOfCollectedSignatures)"
|
||||||
|
AffirmationCompleted = "event AffirmationCompleted(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status)"
|
||||||
|
LegacyAffirmationCompleted = "event AffirmationCompleted(address sender, address executor, bytes32 messageId, bool status)"
|
||||||
|
RelayedMessage = "event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status)"
|
||||||
|
LegacyRelayedMessage = "event RelayedMessage(address sender, address executor, bytes32 messageId, bool status)"
|
||||||
|
InformationRetrieved = "event InformationRetrieved(bytes32 indexed messageId, bool status, bool callbackStatus)"
|
||||||
|
|
||||||
|
ErcToNativeUserRequestForSignature = "event UserRequestForSignature(address recipient, uint256 value)"
|
||||||
|
ErcToNativeTransfer = "event Transfer(address indexed from, address indexed to, uint256 value)"
|
||||||
|
ErcToNativeRelayedMessage = "event RelayedMessage(address recipient, uint256 value, bytes32 transactionHash)"
|
||||||
|
ErcToNativeUserRequestForAffirmation = "event UserRequestForAffirmation(address recipient, uint256 value)"
|
||||||
|
ErcToNativeAffirmationCompleted = "event AffirmationCompleted(address recipient, uint256 value, bytes32 transactionHash)"
|
||||||
|
ErcToNativeSignedForAffirmation = "event SignedForAffirmation(address indexed signer, bytes32 transactionHash)"
|
||||||
|
|
||||||
|
ValidatorAdded = "event ValidatorAdded(address indexed validator)"
|
||||||
|
ValidatorRemoved = "event ValidatorRemoved(address indexed validator)"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ArbitraryMessageABI = abi.MustReadABI(arbitraryMessageJSONABI)
|
||||||
|
ErcToNativeABI = abi.MustReadABI(ercToNativeJSONABI)
|
||||||
|
|
||||||
|
ErcToNativeTransferEventSignature = ErcToNativeABI.Events["Transfer"].ID
|
||||||
|
ErcToNativeUserRequestForAffirmationEventSignature = ErcToNativeABI.Events["UserRequestForAffirmation"].ID
|
||||||
|
)
|
|
@ -0,0 +1,16 @@
|
||||||
|
package bridgeabi_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/poanetwork/tokenbridge-monitor/contract/bridgeabi"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEventSignatures(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
require.NotZero(t, bridgeabi.ErcToNativeTransferEventSignature)
|
||||||
|
require.NotZero(t, bridgeabi.ErcToNativeUserRequestForAffirmationEventSignature)
|
||||||
|
}
|
|
@ -5,38 +5,29 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/poanetwork/tokenbridge-monitor/entity"
|
"github.com/poanetwork/tokenbridge-monitor/contract/abi"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Contract struct {
|
type Contract struct {
|
||||||
address common.Address
|
|
||||||
client ethclient.Client
|
client ethclient.Client
|
||||||
abi abi.ABI
|
Address common.Address
|
||||||
|
ABI abi.ABI
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContract(client ethclient.Client, addr common.Address, abi abi.ABI) *Contract {
|
func NewContract(client ethclient.Client, addr common.Address, abi abi.ABI) *Contract {
|
||||||
return &Contract{addr, client, abi}
|
return &Contract{client, addr, abi}
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Contract) AllEvents() map[string]bool {
|
|
||||||
events := make(map[string]bool, len(c.abi.Events))
|
|
||||||
for _, event := range c.abi.Events {
|
|
||||||
events[event.String()] = true
|
|
||||||
}
|
|
||||||
return events
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Contract) Call(ctx context.Context, method string, args ...interface{}) ([]byte, error) {
|
func (c *Contract) Call(ctx context.Context, method string, args ...interface{}) ([]byte, error) {
|
||||||
data, err := c.abi.Pack(method, args...)
|
data, err := c.ABI.Pack(method, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot encode abi calldata: %w", err)
|
return nil, fmt.Errorf("cannot encode abi calldata: %w", err)
|
||||||
}
|
}
|
||||||
res, err := c.client.CallContract(ctx, ethereum.CallMsg{
|
res, err := c.client.CallContract(ctx, ethereum.CallMsg{
|
||||||
To: &c.address,
|
To: &c.Address,
|
||||||
Data: data,
|
Data: data,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -44,7 +35,3 @@ func (c *Contract) Call(ctx context.Context, method string, args ...interface{})
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Contract) ParseLog(log *entity.Log) (string, map[string]interface{}, error) {
|
|
||||||
return ParseLog(c.abi, log)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
package contract
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
|
|
||||||
"github.com/poanetwork/tokenbridge-monitor/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrInvalidEvent = errors.New("invalid event")
|
|
||||||
|
|
||||||
func Indexed(args abi.Arguments) abi.Arguments {
|
|
||||||
var indexed abi.Arguments
|
|
||||||
for _, arg := range args {
|
|
||||||
if arg.Indexed {
|
|
||||||
indexed = append(indexed, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return indexed
|
|
||||||
}
|
|
||||||
|
|
||||||
func FindMatchingEventABI(contractABI abi.ABI, topics []common.Hash) *abi.Event {
|
|
||||||
for _, e := range contractABI.Events {
|
|
||||||
if e.ID == topics[0] {
|
|
||||||
indexed := Indexed(e.Inputs)
|
|
||||||
if len(indexed) == len(topics)-1 {
|
|
||||||
return &e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeEventLog(event *abi.Event, topics []common.Hash, data []byte) (map[string]interface{}, error) {
|
|
||||||
indexed := Indexed(event.Inputs)
|
|
||||||
values := make(map[string]interface{})
|
|
||||||
if len(indexed) < len(event.Inputs) {
|
|
||||||
if err := event.Inputs.UnpackIntoMap(values, data); err != nil {
|
|
||||||
return nil, fmt.Errorf("can't unpack data: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := abi.ParseTopicsIntoMap(values, indexed, topics[1:]); err != nil {
|
|
||||||
return nil, fmt.Errorf("can't unpack topics: %w", err)
|
|
||||||
}
|
|
||||||
return values, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseLog(contractABI abi.ABI, log *entity.Log) (string, map[string]interface{}, error) {
|
|
||||||
topics := log.Topics()
|
|
||||||
if len(topics) == 0 {
|
|
||||||
return "", nil, fmt.Errorf("cannot process event without topics: %w", ErrInvalidEvent)
|
|
||||||
}
|
|
||||||
event := FindMatchingEventABI(contractABI, topics)
|
|
||||||
if event == nil {
|
|
||||||
return "", nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := DecodeEventLog(event, topics, log.Data)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("can't decode event log: %w", err)
|
|
||||||
}
|
|
||||||
return event.String(), res, nil
|
|
||||||
}
|
|
|
@ -118,7 +118,7 @@ func (m *ContractMonitor) RegisterEventHandler(event string, handler EventHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *ContractMonitor) VerifyEventHandlersABI() error {
|
func (m *ContractMonitor) VerifyEventHandlersABI() error {
|
||||||
events := m.contract.AllEvents()
|
events := m.contract.ABI.AllEvents()
|
||||||
for e := range m.eventHandlers {
|
for e := range m.eventHandlers {
|
||||||
if !events[e] {
|
if !events[e] {
|
||||||
return fmt.Errorf("contract does not have %s event in its ABI: %w", e, ErrIncompatibleABI)
|
return fmt.Errorf("contract does not have %s event in its ABI: %w", e, ErrIncompatibleABI)
|
||||||
|
@ -466,7 +466,7 @@ func (m *ContractMonitor) tryToProcessLogsBatch(ctx context.Context, batch *Logs
|
||||||
"block_number": batch.BlockNumber,
|
"block_number": batch.BlockNumber,
|
||||||
}).Debug("processing logs batch")
|
}).Debug("processing logs batch")
|
||||||
for _, log := range batch.Logs {
|
for _, log := range batch.Logs {
|
||||||
event, data, err := m.contract.ParseLog(log)
|
event, data, err := m.contract.ABI.ParseLog(log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't parse log: %w", err)
|
return fmt.Errorf("can't parse log: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
"github.com/poanetwork/tokenbridge-monitor/config"
|
"github.com/poanetwork/tokenbridge-monitor/config"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/contract/abi"
|
"github.com/poanetwork/tokenbridge-monitor/contract/bridgeabi"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/db"
|
"github.com/poanetwork/tokenbridge-monitor/db"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/entity"
|
"github.com/poanetwork/tokenbridge-monitor/entity"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
||||||
|
@ -96,7 +96,7 @@ func (p *BridgeEventHandler) HandleErcToNativeTransfer(ctx context.Context, log
|
||||||
FromBlock: &log.BlockNumber,
|
FromBlock: &log.BlockNumber,
|
||||||
ToBlock: &log.BlockNumber,
|
ToBlock: &log.BlockNumber,
|
||||||
TxHash: &log.TransactionHash,
|
TxHash: &log.TransactionHash,
|
||||||
Topic0: &abi.ErcToNativeUserRequestForAffirmationEventSignature,
|
Topic0: &bridgeabi.ErcToNativeUserRequestForAffirmationEventSignature,
|
||||||
}
|
}
|
||||||
logs, err := p.repo.Logs.Find(ctx, filter)
|
logs, err := p.repo.Logs.Find(ctx, filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -153,7 +153,7 @@ func (p *BridgeEventHandler) HandleErcToNativeUserRequestForAffirmation(ctx cont
|
||||||
FromBlock: &log.BlockNumber,
|
FromBlock: &log.BlockNumber,
|
||||||
ToBlock: &log.BlockNumber,
|
ToBlock: &log.BlockNumber,
|
||||||
TxHash: &log.TransactionHash,
|
TxHash: &log.TransactionHash,
|
||||||
Topic0: &abi.ErcToNativeTransferEventSignature,
|
Topic0: &bridgeabi.ErcToNativeTransferEventSignature,
|
||||||
Topic2: hashPtr(p.cfg.Foreign.Address.Hash()),
|
Topic2: hashPtr(p.cfg.Foreign.Address.Hash()),
|
||||||
DataLength: uintPtr(32),
|
DataLength: uintPtr(32),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/poanetwork/tokenbridge-monitor/config"
|
"github.com/poanetwork/tokenbridge-monitor/config"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/contract/abi"
|
"github.com/poanetwork/tokenbridge-monitor/contract/bridgeabi"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/db"
|
"github.com/poanetwork/tokenbridge-monitor/db"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
"github.com/poanetwork/tokenbridge-monitor/ethclient"
|
||||||
"github.com/poanetwork/tokenbridge-monitor/logging"
|
"github.com/poanetwork/tokenbridge-monitor/logging"
|
||||||
|
@ -63,42 +63,42 @@ func NewMonitor(ctx context.Context, logger logging.Logger, dbConn *db.DB, repo
|
||||||
|
|
||||||
func (m *Monitor) RegisterErcToNativeEventHandlers() {
|
func (m *Monitor) RegisterErcToNativeEventHandlers() {
|
||||||
handlers := NewBridgeEventHandler(m.repo, m.cfg, m.homeMonitor.client)
|
handlers := NewBridgeEventHandler(m.repo, m.cfg, m.homeMonitor.client)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ErcToNativeUserRequestForSignature, handlers.HandleErcToNativeUserRequestForSignature)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ErcToNativeUserRequestForSignature, handlers.HandleErcToNativeUserRequestForSignature)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.SignedForUserRequest, handlers.HandleSignedForUserRequest)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.SignedForUserRequest, handlers.HandleSignedForUserRequest)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.CollectedSignatures, handlers.HandleCollectedSignatures)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.CollectedSignatures, handlers.HandleCollectedSignatures)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ErcToNativeSignedForAffirmation, handlers.HandleErcToNativeSignedForAffirmation)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ErcToNativeSignedForAffirmation, handlers.HandleErcToNativeSignedForAffirmation)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ErcToNativeAffirmationCompleted, handlers.HandleErcToNativeAffirmationCompleted)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ErcToNativeAffirmationCompleted, handlers.HandleErcToNativeAffirmationCompleted)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ValidatorAdded, handlers.HandleValidatorAdded)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ValidatorAdded, handlers.HandleValidatorAdded)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
||||||
|
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ErcToNativeUserRequestForAffirmation, handlers.HandleErcToNativeUserRequestForAffirmation)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ErcToNativeUserRequestForAffirmation, handlers.HandleErcToNativeUserRequestForAffirmation)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ErcToNativeTransfer, handlers.HandleErcToNativeTransfer)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ErcToNativeTransfer, handlers.HandleErcToNativeTransfer)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ErcToNativeRelayedMessage, handlers.HandleErcToNativeRelayedMessage)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ErcToNativeRelayedMessage, handlers.HandleErcToNativeRelayedMessage)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ValidatorAdded, handlers.HandleValidatorAdded)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ValidatorAdded, handlers.HandleValidatorAdded)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Monitor) RegisterAMBEventHandlers() {
|
func (m *Monitor) RegisterAMBEventHandlers() {
|
||||||
handlers := NewBridgeEventHandler(m.repo, m.cfg, m.homeMonitor.client)
|
handlers := NewBridgeEventHandler(m.repo, m.cfg, m.homeMonitor.client)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.UserRequestForSignature, handlers.HandleUserRequestForSignature)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.UserRequestForSignature, handlers.HandleUserRequestForSignature)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.LegacyUserRequestForSignature, handlers.HandleLegacyUserRequestForSignature)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.LegacyUserRequestForSignature, handlers.HandleLegacyUserRequestForSignature)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.SignedForUserRequest, handlers.HandleSignedForUserRequest)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.SignedForUserRequest, handlers.HandleSignedForUserRequest)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.CollectedSignatures, handlers.HandleCollectedSignatures)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.CollectedSignatures, handlers.HandleCollectedSignatures)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.SignedForAffirmation, handlers.HandleSignedForUserRequest)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.SignedForAffirmation, handlers.HandleSignedForUserRequest)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.AffirmationCompleted, handlers.HandleAffirmationCompleted)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.AffirmationCompleted, handlers.HandleAffirmationCompleted)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.LegacyAffirmationCompleted, handlers.HandleAffirmationCompleted)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.LegacyAffirmationCompleted, handlers.HandleAffirmationCompleted)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.UserRequestForInformation, handlers.HandleUserRequestForInformation)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.UserRequestForInformation, handlers.HandleUserRequestForInformation)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.SignedForInformation, handlers.HandleSignedForInformation)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.SignedForInformation, handlers.HandleSignedForInformation)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.InformationRetrieved, handlers.HandleInformationRetrieved)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.InformationRetrieved, handlers.HandleInformationRetrieved)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ValidatorAdded, handlers.HandleValidatorAdded)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ValidatorAdded, handlers.HandleValidatorAdded)
|
||||||
m.homeMonitor.RegisterEventHandler(abi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
m.homeMonitor.RegisterEventHandler(bridgeabi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
||||||
|
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.UserRequestForAffirmation, handlers.HandleUserRequestForAffirmation)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.UserRequestForAffirmation, handlers.HandleUserRequestForAffirmation)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.LegacyUserRequestForAffirmation, handlers.HandleLegacyUserRequestForAffirmation)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.LegacyUserRequestForAffirmation, handlers.HandleLegacyUserRequestForAffirmation)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.RelayedMessage, handlers.HandleRelayedMessage)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.RelayedMessage, handlers.HandleRelayedMessage)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.LegacyRelayedMessage, handlers.HandleRelayedMessage)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.LegacyRelayedMessage, handlers.HandleRelayedMessage)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ValidatorAdded, handlers.HandleValidatorAdded)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ValidatorAdded, handlers.HandleValidatorAdded)
|
||||||
m.foreignMonitor.RegisterEventHandler(abi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
m.foreignMonitor.RegisterEventHandler(bridgeabi.ValidatorRemoved, handlers.HandleValidatorRemoved)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Monitor) Start(ctx context.Context) {
|
func (m *Monitor) Start(ctx context.Context) {
|
||||||
|
|
Loading…
Reference in New Issue