Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

relayer, update WaitReceipt to return MetaTxnReceipt #128

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ toolchain go1.22.0
// replace github.com/0xsequence/ethkit => /Users/peter/Dev/0xsequence/ethkit

require (
github.com/0xsequence/ethkit v1.24.9
github.com/0xsequence/ethkit v1.24.10
github.com/0xsequence/go-ethauth v0.13.0
github.com/BurntSushi/toml v1.2.1
github.com/davecgh/go-spew v1.1.1
github.com/gibson042/canonicaljson-go v1.0.3
github.com/goware/breaker v0.1.2
github.com/goware/cachestore v0.8.1
github.com/goware/logger v0.3.0
github.com/shopspring/decimal v1.3.1
Expand All @@ -31,6 +30,7 @@ require (
github.com/go-stack/stack v1.8.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/goware/breaker v0.1.2 // indirect
github.com/goware/calc v0.2.0 // indirect
github.com/goware/channel v0.4.1 // indirect
github.com/goware/singleflight v0.2.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
github.com/0xsequence/ethkit v1.24.9 h1:yOVmMc4fJ5NjSPr9piX6rjveqYFsgqKOMxqKRLUiRW4=
github.com/0xsequence/ethkit v1.24.9/go.mod h1:E3eymNtV0oJabgqM9R92xTQYOsT7rVHxFRju8A2CFJw=
github.com/0xsequence/ethkit v1.24.10 h1:aWAbCmadC2GlzoXn96uQ+8V1UWcBxO01F+DtIxsFqXM=
github.com/0xsequence/ethkit v1.24.10/go.mod h1:E3eymNtV0oJabgqM9R92xTQYOsT7rVHxFRju8A2CFJw=
github.com/0xsequence/go-ethauth v0.13.0 h1:ZaqFEEqy574A2b1P7vjpcy5tb4W/izn+A3swwOYi9wA=
github.com/0xsequence/go-ethauth v0.13.0/go.mod h1:f3kx39S9F+W+qvZEB6bkKKbpUstmyB7goUntO3wvlhg=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
Expand Down
55 changes: 41 additions & 14 deletions receipts.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ func (r *Receipt) setNativeReceipt(receipt *types.Receipt) {

// This method is duplicated code from: `compressor/contract.go`
// can't be used directly, because it would create a circular dependency
func DecompressCalldata(ctx context.Context, provider *ethrpc.Provider, transaction *types.Transaction) (common.Address, []byte, error) {
data := transaction.Data()
func DecompressCalldata(
ctx context.Context,
provider *ethrpc.Provider,
toAddress common.Address,
calldata []byte,
) (common.Address, []byte, error) {
data := calldata

if len(data) == 0 {
return common.Address{}, nil, fmt.Errorf("empty transaction data")
Expand All @@ -74,7 +79,7 @@ func DecompressCalldata(ctx context.Context, provider *ethrpc.Provider, transact
c2[0] = byte(0x06)

res, err := provider.CallContract(ctx, ethereum.CallMsg{
To: transaction.To(),
To: &toAddress,
Data: c2,
}, nil)

Expand All @@ -93,18 +98,26 @@ func DecompressCalldata(ctx context.Context, provider *ethrpc.Provider, transact
func TryDecodeCalldata(
ctx context.Context,
provider *ethrpc.Provider,
transaction *types.Transaction,
toAddress common.Address,
calldata []byte,
decompressCzip bool,
) (common.Address, Transactions, *big.Int, []byte, error) {
decodedTransactions, decodedNonce, decodedSignature, err := DecodeExecdata(transaction.Data())
decodedTransactions, decodedNonce, decodedSignature, err := DecodeExecdata(calldata)
if err == nil {
return *transaction.To(), decodedTransactions, decodedNonce, decodedSignature, nil
return toAddress, decodedTransactions, decodedNonce, decodedSignature, nil
}

var addr common.Address
var decompressed []byte
var err2 error

// Try decoding it decompressed
addr, decompressed, err2 := DecompressCalldata(ctx, provider, transaction)
if err2 != nil {
// Don't bubble up the decompression error, as it might not be a decompression error
return common.Address{}, nil, nil, nil, err
if decompressCzip {
addr, decompressed, err2 = DecompressCalldata(ctx, provider, toAddress, calldata)
if err2 != nil {
// Don't bubble up the decompression error, as it might not be a decompression error
return common.Address{}, nil, nil, nil, err
}
}

decodedTransactions, decodedNonce, decodedSignature, err = DecodeExecdata(decompressed)
Expand All @@ -115,19 +128,33 @@ func TryDecodeCalldata(
return addr, decodedTransactions, decodedNonce, decodedSignature, nil
}

func DecodeReceipt(ctx context.Context, receipt *types.Receipt, provider *ethrpc.Provider) ([]*Receipt, []*types.Log, error) {
transaction, _, err := provider.TransactionByHash(ctx, receipt.TxHash)
func DecodeReceipt(
ctx context.Context,
receipt *types.Receipt,
provider *ethrpc.Provider,
calldata []byte,
decompressCzip bool,
) ([]*Receipt, []*types.Log, error) {
if calldata == nil {
transaction, _, err := provider.TransactionByHash(ctx, receipt.TxHash)
if err != nil {
return nil, nil, err
}
calldata = transaction.Data()
}

chainID, err := provider.ChainID(ctx)
if err != nil {
return nil, nil, err
}

wallet, decodedTransactions, decodedNonce, decodedSignature, err := TryDecodeCalldata(ctx, provider, transaction)
wallet, decodedTransactions, decodedNonce, decodedSignature, err := TryDecodeCalldata(ctx, provider, receipt.To, calldata, decompressCzip)
if err != nil {
return nil, nil, err
}

isGuestExecute := decodedNonce != nil && len(decodedSignature) == 0
logs, receipts, err := decodeReceipt(receipt.Logs, decodedTransactions, decodedNonce, wallet, transaction.ChainId(), isGuestExecute)
logs, receipts, err := decodeReceipt(receipt.Logs, decodedTransactions, decodedNonce, wallet, chainID, isGuestExecute)
if err != nil {
return nil, nil, err
}
Expand Down
7 changes: 4 additions & 3 deletions relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"time"

"github.com/0xsequence/ethkit/ethrpc"
"github.com/0xsequence/ethkit/ethtxn"
"github.com/0xsequence/ethkit/go-ethereum/common"
"github.com/0xsequence/ethkit/go-ethereum/core/types"
"github.com/0xsequence/go-sequence/contracts"
Expand Down Expand Up @@ -68,13 +67,13 @@ type Relayer interface {
// Relay will submit the Sequence signed meta transaction to the relayer. The method will block until the relayer
// responds with the native transaction hash (*types.Transaction), which means the relayer has submitted the transaction
// request to the network. Clients can use WaitReceipt to wait until the metaTxnID has been mined.
Relay(ctx context.Context, signedTxs *SignedTransactions, quote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error)
Relay(ctx context.Context, signedTxs *SignedTransactions, quote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, WaitReceipt, error)

//
FeeOptions(ctx context.Context, signedTxs *SignedTransactions) ([]*RelayerFeeOption, *RelayerFeeQuote, error)

// ..
Wait(ctx context.Context, metaTxnID MetaTxnID, optTimeout ...time.Duration) (MetaTxnStatus, *types.Receipt, error)
Wait(ctx context.Context, metaTxnID MetaTxnID, optTimeout ...time.Duration) (MetaTxnStatus, *types.Receipt, *proto.MetaTxnReceipt, error)

// ..
Client() proto.Relayer
Expand All @@ -98,6 +97,8 @@ const (
MetaTxnReverted
)

type WaitReceipt func(ctx context.Context) (*types.Receipt, *proto.MetaTxnReceipt, error)

// returns `to` address (either guest or wallet) and `data` of signed-metatx-calldata, aka execdata
func EncodeTransactionsForRelaying(relayer Relayer, walletAddress common.Address, walletConfig core.WalletConfig, walletContext WalletContext, txns Transactions, nonce *big.Int, seqSig []byte) (common.Address, []byte, error) {
// TODO/NOTE: first version, we assume the wallet is deployed, then we can add bundlecreation after.
Expand Down
18 changes: 12 additions & 6 deletions relayer/local_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (r *LocalRelayer) Simulate(ctx context.Context, txs *sequence.SignedTransac
panic("implement me")
}

func (r *LocalRelayer) Relay(ctx context.Context, signedTxs *sequence.SignedTransactions, quote ...*sequence.RelayerFeeQuote) (sequence.MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) {
func (r *LocalRelayer) Relay(ctx context.Context, signedTxs *sequence.SignedTransactions, quote ...*sequence.RelayerFeeQuote) (sequence.MetaTxnID, *types.Transaction, sequence.WaitReceipt, error) {
// NOTE: this implementation assumes the wallet is deployed and does not do automatic bundle creation (aka prepending / bundling
// a wallet creation call)

Expand Down Expand Up @@ -208,27 +208,33 @@ func (r *LocalRelayer) Relay(ctx context.Context, signedTxs *sequence.SignedTran
return metaTxnID, nil, nil, err
}

ntx, waitReceipt, err := sender.SendTransaction(ctx, signedTx)
ntx, _, err = sender.SendTransaction(ctx, signedTx)
if err != nil {
return metaTxnID, nil, nil, err
}

waitReceipt := func(ctx context.Context) (*types.Receipt, *proto.MetaTxnReceipt, error) {
// NOTE: to timeout the request, pass a ctx from context.WithTimeout
_, receipt, metaTxnReceipt, err := r.Wait(ctx, sequence.MetaTxnID(metaTxnID))
return receipt, metaTxnReceipt, err
}

return metaTxnID, ntx, waitReceipt, nil
}

func (r *LocalRelayer) Wait(ctx context.Context, metaTxnID sequence.MetaTxnID, optTimeout ...time.Duration) (sequence.MetaTxnStatus, *types.Receipt, error) {
func (r *LocalRelayer) Wait(ctx context.Context, metaTxnID sequence.MetaTxnID, optTimeout ...time.Duration) (sequence.MetaTxnStatus, *types.Receipt, *proto.MetaTxnReceipt, error) {
if r.receiptListener == nil {
return 0, nil, fmt.Errorf("relayer: failed to wait for metaTxnID as receiptListener is not set")
return 0, nil, nil, fmt.Errorf("relayer: failed to wait for metaTxnID as receiptListener is not set")
}
result, receipt, _, err := sequence.FetchMetaTransactionReceipt(ctx, r.receiptListener, metaTxnID, optTimeout...)
if err != nil {
return 0, nil, err
return 0, nil, nil, err
}
var status sequence.MetaTxnStatus
if result != nil {
status = result.Status
}
return status, receipt.Receipt(), nil
return status, receipt.Receipt(), nil, nil // XXXXXX
}

func (r *LocalRelayer) FeeOptions(ctx context.Context, signedTxs *sequence.SignedTransactions) ([]*sequence.RelayerFeeOption, *sequence.RelayerFeeQuote, error) {
Expand Down
29 changes: 15 additions & 14 deletions relayer/rpc_relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/0xsequence/ethkit"
"github.com/0xsequence/ethkit/ethreceipts"
"github.com/0xsequence/ethkit/ethrpc"
"github.com/0xsequence/ethkit/ethtxn"
"github.com/0xsequence/ethkit/go-ethereum/common"
"github.com/0xsequence/ethkit/go-ethereum/common/hexutil"
"github.com/0xsequence/ethkit/go-ethereum/core/types"
Expand Down Expand Up @@ -144,7 +143,7 @@ func (r *RpcRelayer) Simulate(ctx context.Context, txs *sequence.SignedTransacti
// Relay will submit the Sequence signed meta transaction to the relayer. The method will block until the relayer
// responds with the native transaction hash (*types.Transaction), which means the relayer has submitted the transaction
// request to the network. Clients can use WaitReceipt to wait until the metaTxnID has been mined.
func (r *RpcRelayer) Relay(ctx context.Context, signedTxs *sequence.SignedTransactions, quote ...*sequence.RelayerFeeQuote) (sequence.MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) {
func (r *RpcRelayer) Relay(ctx context.Context, signedTxs *sequence.SignedTransactions, quote ...*sequence.RelayerFeeQuote) (sequence.MetaTxnID, *types.Transaction, sequence.WaitReceipt, error) {
walletAddress := signedTxs.WalletAddress
var err error

Expand Down Expand Up @@ -196,10 +195,10 @@ func (r *RpcRelayer) Relay(ctx context.Context, signedTxs *sequence.SignedTransa
return "", nil, nil, proto.Failf("failed to relay meta transaction: server returned empty metaTxnID")
}

waitReceipt := func(ctx context.Context) (*types.Receipt, error) {
waitReceipt := func(ctx context.Context) (*types.Receipt, *proto.MetaTxnReceipt, error) {
// NOTE: to timeout the request, pass a ctx from context.WithTimeout
_, receipt, err := r.Wait(ctx, sequence.MetaTxnID(metaTxnID))
return receipt, err
_, receipt, metaTxnReceipt, err := r.Wait(ctx, sequence.MetaTxnID(metaTxnID))
return receipt, metaTxnReceipt, err
}

// TODO: 2nd argument will be nil, we may even want to remove it from here...
Expand Down Expand Up @@ -232,7 +231,7 @@ func (r *RpcRelayer) FeeOptions(ctx context.Context, signedTxs *sequence.SignedT
}

// ....
func (r *RpcRelayer) Wait(ctx context.Context, metaTxnID sequence.MetaTxnID, optTimeout ...time.Duration) (sequence.MetaTxnStatus, *types.Receipt, error) {
func (r *RpcRelayer) Wait(ctx context.Context, metaTxnID sequence.MetaTxnID, optTimeout ...time.Duration) (sequence.MetaTxnStatus, *types.Receipt, *proto.MetaTxnReceipt, error) {
// Fetch the meta transaction receipt from the relayer service
if r.receiptListener == nil {
return r.waitMetaTxnReceipt(ctx, metaTxnID, optTimeout...)
Expand All @@ -241,16 +240,18 @@ func (r *RpcRelayer) Wait(ctx context.Context, metaTxnID sequence.MetaTxnID, opt
// Fetch the meta transaction receipt from the receipt listener
result, receipt, _, err := sequence.FetchMetaTransactionReceipt(ctx, r.receiptListener, metaTxnID, optTimeout...)
if err != nil {
return 0, nil, err
return 0, nil, nil, err
}
var status sequence.MetaTxnStatus
if result != nil {
status = result.Status
}
return status, receipt.Receipt(), nil
// TODO: need to get from receipt listener result to a sequence meta txn receipt ..
// TODO: can copy bunch of code from GetMetaTxnReceipt .. using sequence.DecodeReceipt(receipt) etc..
return status, receipt.Receipt(), nil, nil // XXXX
}

func (r *RpcRelayer) waitMetaTxnReceipt(ctx context.Context, metaTxnID sequence.MetaTxnID, optTimeout ...time.Duration) (sequence.MetaTxnStatus, *types.Receipt, error) {
func (r *RpcRelayer) waitMetaTxnReceipt(ctx context.Context, metaTxnID sequence.MetaTxnID, optTimeout ...time.Duration) (sequence.MetaTxnStatus, *types.Receipt, *proto.MetaTxnReceipt, error) {
// TODO: in future GetMetaTxnReceipt() will be renamed to WaitTransactionReceipt()

var clear context.CancelFunc
Expand All @@ -264,9 +265,9 @@ func (r *RpcRelayer) waitMetaTxnReceipt(ctx context.Context, metaTxnID sequence.
case <-ctx.Done():
err := ctx.Err()
if err != nil {
return 0, nil, err
return 0, nil, nil, err
}
return 0, nil, nil
return 0, nil, nil, nil
default:
}

Expand All @@ -278,15 +279,15 @@ func (r *RpcRelayer) waitMetaTxnReceipt(ctx context.Context, metaTxnID sequence.
continue
}
if err != nil {
return sequence.MetaTxnStatusUnknown, nil, err
return sequence.MetaTxnStatusUnknown, nil, nil, err
}
txnReceipt := metaTxnReceipt.TxnReceipt
var receipt *types.Receipt
err = json.Unmarshal([]byte(txnReceipt), &receipt)
if err != nil {
return 0, nil, fmt.Errorf("failed to decode txn receipt data: %w", err)
return 0, nil, nil, fmt.Errorf("failed to decode txn receipt data: %w", err)
}
return MetaTxnStatusFromString(metaTxnReceipt.Status), receipt, nil
return MetaTxnStatusFromString(metaTxnReceipt.Status), receipt, metaTxnReceipt, nil
}
}

Expand Down
10 changes: 8 additions & 2 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
"github.com/0xsequence/go-sequence/core"
v1 "github.com/0xsequence/go-sequence/core/v1"
v2 "github.com/0xsequence/go-sequence/core/v2"
"github.com/0xsequence/go-sequence/relayer/proto"
)

var zeroAddress = common.Address{}

func DeploySequenceWallet(sender *ethwallet.Wallet, walletConfig core.WalletConfig, walletContext WalletContext) (common.Address, *types.Transaction, ethtxn.WaitReceipt, error) {
func DeploySequenceWallet(sender *ethwallet.Wallet, walletConfig core.WalletConfig, walletContext WalletContext) (common.Address, *types.Transaction, WaitReceipt, error) {
if sender.GetProvider() == nil {
return common.Address{}, nil, nil, ErrProviderNotSet
}
Expand Down Expand Up @@ -48,7 +49,12 @@ func DeploySequenceWallet(sender *ethwallet.Wallet, walletConfig core.WalletConf

tx, waitReceipt, err := sender.SendTransaction(context.Background(), signedDeployTx)

return walletAddress, tx, waitReceipt, nil
metaTxnWaitReceipt := func(ctx context.Context) (*types.Receipt, *proto.MetaTxnReceipt, error) {
receipt, err := waitReceipt(ctx)
return receipt, nil, err
}

return walletAddress, tx, metaTxnWaitReceipt, err
}

func EncodeWalletDeployment(walletConfig core.WalletConfig, walletContext WalletContext) (common.Address, common.Address, []byte, error) {
Expand Down
4 changes: 2 additions & 2 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestDeploySequenceWallet(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, tx)

receipt, err := waitReceipt(context.Background())
receipt, _, err := waitReceipt(context.Background())
assert.NoError(t, err)
assert.True(t, receipt.Status == types.ReceiptStatusSuccessful)

Expand Down Expand Up @@ -77,7 +77,7 @@ func TestDeploySequenceWallet(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, tx)

receipt, err := waitReceipt(context.Background())
receipt, _, err := waitReceipt(context.Background())
assert.NoError(t, err)
assert.True(t, receipt.Status == types.ReceiptStatusSuccessful)

Expand Down
7 changes: 3 additions & 4 deletions wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"github.com/0xsequence/ethkit/ethcoder"
"github.com/0xsequence/ethkit/ethrpc"
"github.com/0xsequence/ethkit/ethtxn"
"github.com/0xsequence/ethkit/go-ethereum/common"
"github.com/0xsequence/ethkit/go-ethereum/core/types"
"github.com/0xsequence/go-sequence/core"
Expand Down Expand Up @@ -577,11 +576,11 @@ func (w *Wallet[C]) SignTransactions(ctx context.Context, txns Transactions) (*S
}, nil
}

func (w *Wallet[C]) SendTransaction(ctx context.Context, signedTxns *SignedTransactions, feeQuote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) {
func (w *Wallet[C]) SendTransaction(ctx context.Context, signedTxns *SignedTransactions, feeQuote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, WaitReceipt, error) {
return w.SendTransactions(ctx, signedTxns, feeQuote...)
}

func (w *Wallet[C]) SendTransactions(ctx context.Context, signedTxns *SignedTransactions, feeQuote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) {
func (w *Wallet[C]) SendTransactions(ctx context.Context, signedTxns *SignedTransactions, feeQuote ...*RelayerFeeQuote) (MetaTxnID, *types.Transaction, WaitReceipt, error) {
if w.relayer == nil {
return "", nil, nil, ErrRelayerNotSet
}
Expand Down Expand Up @@ -654,7 +653,7 @@ func (w *Wallet[C]) IsDeployed() (bool, error) {
return IsWalletDeployed(w.provider, w.Address())
}

func (w *Wallet[C]) Deploy(ctx context.Context) (MetaTxnID, *types.Transaction, ethtxn.WaitReceipt, error) {
func (w *Wallet[C]) Deploy(ctx context.Context) (MetaTxnID, *types.Transaction, WaitReceipt, error) {
if w.relayer == nil {
return "", nil, nil, ErrRelayerNotSet
}
Expand Down
Loading