Skip to content

Commit

Permalink
feat: add erc1155 listener/handler (#254)
Browse files Browse the repository at this point in the history
  • Loading branch information
tcar121293 authored Mar 21, 2024
1 parent 37039b9 commit 68923e3
Show file tree
Hide file tree
Showing 18 changed files with 614 additions and 101 deletions.
5 changes: 5 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ func Run() error {
depositHandler.RegisterDepositHandler(handler.Address, coreListener.Erc721DepositHandler)
mh.RegisterMessageHandler(handler.Address, coreExecutor.ERC721MessageHandler)
}
case "erc1155":
{
depositHandler.RegisterDepositHandler(handler.Address, listener.Erc1155DepositHandler)
mh.RegisterMessageHandler(handler.Address, executor.Erc1155MessageHandler)
}
}
}
depositListener := coreEvents.NewListener(client)
Expand Down
6 changes: 6 additions & 0 deletions chains/evm/calls/consts/erc1155.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// The Licensed Work is (c) 2022 Sygma
// SPDX-License-Identifier: LGPL-3.0-only

package consts

const ERC1155PresetMinterPauserABI = `[{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"burnBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]`
32 changes: 32 additions & 0 deletions chains/evm/calls/contracts/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/ChainSafe/chainbridge-core/chains/evm/calls"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts/deposit"
syg_deposit "github.com/ChainSafe/sygma-relayer/chains/evm/calls/contracts/deposit"

"github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor"
"github.com/ChainSafe/chainbridge-core/types"
"github.com/ChainSafe/sygma-relayer/chains"
Expand Down Expand Up @@ -128,6 +130,36 @@ func (c *BridgeContract) Erc721Deposit(
return txHash, err
}

func (c *BridgeContract) Erc1155Deposit(
tokenIds *big.Int,
amounts *big.Int,
metadata string,
recipient common.Address,
resourceID types.ResourceID,
destDomainID uint8,
feeData []byte,
opts transactor.TransactOptions,
) (*common.Hash, error) {
log.Debug().
Str("recipient", recipient.String()).
Str("resourceID", hexutil.Encode(resourceID[:])).
Uint8("destDomainID", destDomainID).
Hex("feeData", feeData).
Msgf("ERC1155 deposit")

var data []byte
data, err := syg_deposit.ConstructErc1155DepositData(recipient.Bytes(), tokenIds, amounts, []byte(metadata))
if err != nil {
return nil, err
}
txHash, err := c.deposit(resourceID, destDomainID, data, feeData, opts)
if err != nil {
log.Error().Err(err)
return nil, err
}
return txHash, err
}

func (c *BridgeContract) GenericDeposit(
metadata []byte,
resourceID types.ResourceID,
Expand Down
31 changes: 31 additions & 0 deletions chains/evm/calls/contracts/deposit/deposit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package deposit

import (
"math/big"

"github.com/ChainSafe/sygma-relayer/chains/evm/listener"
)

func ConstructErc1155DepositData(destRecipient []byte, tokenIds *big.Int, amounts *big.Int, metadata []byte) ([]byte, error) {
erc1155Type, err := listener.GetErc1155Type()
if err != nil {
return nil, err
}

payload := []interface{}{
[]*big.Int{
tokenIds,
},
[]*big.Int{
amounts,
},
destRecipient,
[]byte{},
}
data, err := erc1155Type.Pack(payload...)

if err != nil {
return nil, err
}
return data, nil
}
53 changes: 53 additions & 0 deletions chains/evm/calls/contracts/erc1155/erc1155.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package erc1155

import (
"math/big"
"strings"

"github.com/ChainSafe/chainbridge-core/chains/evm/calls"
"github.com/ChainSafe/chainbridge-core/chains/evm/calls/contracts"
"github.com/ChainSafe/sygma-relayer/chains/evm/calls/consts"

"github.com/ChainSafe/chainbridge-core/chains/evm/calls/transactor"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/rs/zerolog/log"
)

type ERC1155Contract struct {
contracts.Contract
}

func NewErc1155Contract(
client calls.ContractCallerDispatcher,
erc1155ContractAddress common.Address,
t transactor.Transactor,
) *ERC1155Contract {
a, _ := abi.JSON(strings.NewReader(consts.ERC1155PresetMinterPauserABI))
b := common.FromHex(consts.ERC1155PresetMinterPauserABI)
return &ERC1155Contract{contracts.NewContract(erc1155ContractAddress, a, b, client, t)}
}

func (c *ERC1155Contract) Approve(
tokenId *big.Int, recipient common.Address, opts transactor.TransactOptions,
) (*common.Hash, error) {
log.Debug().Msgf("Approving %s token for %s", tokenId.String(), recipient.String())
return c.ExecuteTransaction("setApprovalForAll", opts, recipient, true)
}

func (c *ERC1155Contract) Mint(
tokenId *big.Int, amount *big.Int, metadata []byte, destination common.Address, opts transactor.TransactOptions,
) (*common.Hash, error) {
log.Debug().Msgf("Minting tokens %s to %s", tokenId.String(), destination.String())
return c.ExecuteTransaction("mint", opts, destination, tokenId, amount, metadata)
}

func (c *ERC1155Contract) BalanceOf(account common.Address, id *big.Int) (*big.Int, error) {
res, err := c.CallContract("balanceOf", account, id)
if err != nil {
return nil, err
}

amount := abi.ConvertType(res[0], new(big.Int)).(*big.Int)
return amount, nil
}
39 changes: 39 additions & 0 deletions chains/evm/executor/message-handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

"github.com/ChainSafe/chainbridge-core/chains/evm/executor/proposal"
"github.com/ChainSafe/chainbridge-core/relayer/message"
"github.com/ChainSafe/sygma-relayer/chains/evm/listener"
)

func PermissionlessGenericMessageHandler(msg *message.Message, handlerAddr, bridgeAddress common.Address) (*proposal.Proposal, error) {
Expand Down Expand Up @@ -52,3 +53,41 @@ func PermissionlessGenericMessageHandler(msg *message.Message, handlerAddr, brid

return proposal.NewProposal(msg.Source, msg.Destination, msg.DepositNonce, msg.ResourceId, data.Bytes(), handlerAddr, bridgeAddress, msg.Metadata), nil
}

func Erc1155MessageHandler(msg *message.Message, handlerAddr, bridgeAddress common.Address) (*proposal.Proposal, error) {

if len(msg.Payload) != 4 {
return nil, errors.New("malformed payload. Len of payload should be 4")
}
_, ok := msg.Payload[0].([]*big.Int)
if !ok {
return nil, errors.New("wrong payload tokenIDs format")
}
_, ok = msg.Payload[1].([]*big.Int)
if !ok {
return nil, errors.New("wrong payload amounts format")
}
_, ok = msg.Payload[2].([]byte)
if !ok {
return nil, errors.New("wrong payload recipient format")
}
if len(msg.Payload[2].([]byte)) != 20 {
return nil, errors.New("malformed payload. Len of recipient should be 20")
}
_, ok = msg.Payload[3].([]byte)
if !ok {
return nil, errors.New("wrong payload transferData format")
}

erc1155Type, err := listener.GetErc1155Type()
if err != nil {
return nil, err
}

data, err := erc1155Type.PackValues(msg.Payload)
if err != nil {
return nil, err
}

return proposal.NewProposal(msg.Source, msg.Destination, msg.DepositNonce, msg.ResourceId, data, handlerAddr, bridgeAddress, msg.Metadata), nil
}
Loading

0 comments on commit 68923e3

Please sign in to comment.