From 313b25c9eafdf24d2fca39c813d145e1267899ea Mon Sep 17 00:00:00 2001 From: AndresQuijano Date: Thu, 21 Nov 2024 14:34:56 +0000 Subject: [PATCH 1/5] feat: refactor refund user pegout script - add tests --- .../refund_user_pegout/refund_user_pegout.go | 81 +++-------------- .../refund_user_pegout_test.go | 90 +++++++++++++++++++ .../dataproviders/rootstock/bindings.go | 4 +- .../adapters/dataproviders/rootstock/lbc.go | 27 +++++- internal/entities/blockchain/lbc.go | 4 +- test/mocks/abstract_factory_mock.go | 2 +- test/mocks/bitcoin_wallet_mock.go | 2 +- test/mocks/client_adapter_mock.go | 2 +- test/mocks/collection_binding_mock.go | 2 +- test/mocks/db_binding_mock.go | 2 +- test/mocks/db_client_binding_mock.go | 2 +- .../default_credentials_provider_mock.go | 2 +- test/mocks/event_iterator_adapter_mock.go | 2 +- test/mocks/http_client_mock.go | 2 +- test/mocks/lbc_adapter_mock.go | 61 ++++++++++++- test/mocks/lbc_binding_mock.go | 61 ++++++++++++- test/mocks/lbc_mock.go | 6 ++ .../liquidity_provider_repository_mock.go | 2 +- test/mocks/pegin_quote_repository_mock.go | 2 +- test/mocks/pegout_quote_repository_mock.go | 2 +- test/mocks/rootstock_rpc_server_mock.go | 2 +- test/mocks/rpc_client_binding_mock.go | 2 +- test/mocks/rpc_client_mock.go | 2 +- test/mocks/rsk_bridge_binding_mock.go | 2 +- test/mocks/rsk_signer_wallet_mock.go | 2 +- test/mocks/ses_client_mock.go | 2 +- test/mocks/session_binding_mock.go | 2 +- test/mocks/store_mock.go | 2 +- test/mocks/ticker_mock.go | 2 +- test/mocks/transaction_signer_mock.go | 2 +- test/mocks/use_case_registry_mock.go | 2 +- 31 files changed, 280 insertions(+), 100 deletions(-) create mode 100644 cmd/utils/refund_user_pegout/refund_user_pegout_test.go diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout.go b/cmd/utils/refund_user_pegout/refund_user_pegout.go index b10ba721..83216a27 100644 --- a/cmd/utils/refund_user_pegout/refund_user_pegout.go +++ b/cmd/utils/refund_user_pegout/refund_user_pegout.go @@ -4,19 +4,14 @@ import ( "context" "flag" "fmt" - "os" "syscall" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" "github.com/go-playground/validator/v10" "github.com/rsksmart/liquidity-provider-server/cmd/utils/defaults" - "github.com/rsksmart/liquidity-provider-server/internal/adapters/dataproviders/rootstock" - "github.com/rsksmart/liquidity-provider-server/internal/adapters/dataproviders/rootstock/bindings" + "github.com/rsksmart/liquidity-provider-server/cmd/utils/scripts" "github.com/rsksmart/liquidity-provider-server/internal/configuration/bootstrap" - "github.com/rsksmart/liquidity-provider-server/internal/configuration/bootstrap/wallet" "github.com/rsksmart/liquidity-provider-server/internal/configuration/environment" - "github.com/rsksmart/liquidity-provider-server/internal/configuration/environment/secrets" + "github.com/rsksmart/liquidity-provider-server/internal/entities/blockchain" "golang.org/x/term" ) @@ -36,46 +31,24 @@ type RefundUserPegOutScriptInput struct { type PasswordReader = func(int) ([]byte, error) func main() { - ctx := context.Background() - scriptInput := new(RefundUserPegOutScriptInput) ReadRefundUserPegOutScriptInput(scriptInput) env, err := ParseRefundUserPegOutScriptInput(scriptInput, term.ReadPassword) if err != nil { - ExitWithError(2, "Error reading input", err) - } - - rskClient, err := bootstrap.Rootstock(ctx, env.Rsk) - if err != nil { - ExitWithError(2, "Error connecting to RSK node", err) - } - rskWallet, err := GetWallet(ctx, env, rskClient) - if err != nil { - ExitWithError(2, "Error accessing to wallet", err) + scripts.ExitWithError(2, "Error reading input", err) } - err = ExecuteRefundUserPegOut(ctx, env, rskWallet, rskClient, common.HexToHash(scriptInput.QuoteHashBytes)) + ctx := context.Background() + lbc, err := scripts.CreateLiquidityBridgeContract(ctx, bootstrap.Rootstock, env) if err != nil { - ExitWithError(2, "Error on transaction execution", err) + scripts.ExitWithError(2, "Error accessing the Liquidity Bridge Contract", err) } -} -func GetWallet( - ctx context.Context, - env environment.Environment, - rskClient *rootstock.RskClient, -) (rootstock.RskSignerWallet, error) { - secretLoader, err := secrets.GetSecretLoader(ctx, env) + txHash, err := ExecuteRefundUserPegOut(lbc, scriptInput.QuoteHashBytes) if err != nil { - return nil, err + scripts.ExitWithError(2, "Error on transaction execution", err) } - walletFactory, err := wallet.NewFactory(env, wallet.FactoryCreationArgs{ - Ctx: ctx, Env: env, SecretLoader: secretLoader, RskClient: rskClient, - }) - if err != nil { - return nil, err - } - return walletFactory.RskWallet() + fmt.Println("Refund user peg out executed successfully. Transaction hash: ", txHash) } func ReadRefundUserPegOutScriptInput(scriptInput *RefundUserPegOutScriptInput) { @@ -142,38 +115,6 @@ func ParseRefundUserPegOutScriptInput(scriptInput *RefundUserPegOutScriptInput, return env, nil } -func ExecuteRefundUserPegOut( - ctx context.Context, - env environment.Environment, - rskWallet rootstock.RskSignerWallet, - rskClient *rootstock.RskClient, - quoteHashBytes common.Hash, -) error { - lbc, err := bindings.NewLiquidityBridgeContract(common.HexToAddress(env.Rsk.LbcAddress), rskClient.Rpc()) - if err != nil { - return err - } - - opts := &bind.TransactOpts{From: rskWallet.Address(), Signer: rskWallet.Sign} - tx, err := lbc.RefundUserPegOut(opts, quoteHashBytes) - if err != nil { - return err - } - - receipt, err := bind.WaitMined(ctx, rskClient.Rpc(), tx) - if err != nil { - return err - } - - if receipt.Status == 1 { - fmt.Println("Refund user peg out executed successfully. Transaction hash: ", receipt.TxHash.Hex()) - return nil - } else { - return fmt.Errorf("transaction %s failed", receipt.TxHash.Hex()) - } -} - -func ExitWithError(code int, message string, err error) { - fmt.Println(fmt.Sprintf("%s: %s", message, err.Error())) - os.Exit(code) +func ExecuteRefundUserPegOut(lbc blockchain.LiquidityBridgeContract, quoteHash string) (string, error) { + return lbc.RefundUserPegOut(quoteHash) } diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go new file mode 100644 index 00000000..ad0c6f5e --- /dev/null +++ b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go @@ -0,0 +1,90 @@ +package main + +import ( + "flag" + "testing" + + "github.com/rsksmart/liquidity-provider-server/test" + "github.com/rsksmart/liquidity-provider-server/test/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/term" +) + +func TestReadRefundUserPegOutScriptInput(t *testing.T) { + t.Run("should set flag values", func(t *testing.T) { + // Reset flags before test + flag.CommandLine = flag.NewFlagSet("", flag.ExitOnError) + + scriptInput := new(RefundUserPegOutScriptInput) + ReadRefundUserPegOutScriptInput(scriptInput) + + // Set test values + err := flag.CommandLine.Parse([]string{ + "-network", "regtest", + "-quote-hash", "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc", + "-rsk-endpoint", "http://localhost:4444", + "-secret-src", "env", + "-keystore-file", "./keystore.json", + }) + require.NoError(t, err) + + assert.Equal(t, "regtest", scriptInput.Network) + assert.Equal(t, "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc", scriptInput.QuoteHashBytes) + assert.Equal(t, "http://localhost:4444", scriptInput.RskEndpoint) + assert.Equal(t, "env", scriptInput.SecretSource) + assert.Equal(t, "./keystore.json", scriptInput.KeystoreFile) + }) +} + +func TestParseRefundUserPegOutScriptInput(t *testing.T) { + t.Run("should validate required fields", func(t *testing.T) { + scriptInput := &RefundUserPegOutScriptInput{ + Network: "", + QuoteHashBytes: "", + RskEndpoint: "", + SecretSource: "", + } + + _, err := ParseRefundUserPegOutScriptInput(scriptInput, term.ReadPassword) + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid input") + }) + + t.Run("should parse valid input", func(t *testing.T) { + scriptInput := &RefundUserPegOutScriptInput{ + Network: "regtest", + QuoteHashBytes: "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc", + RskEndpoint: "http://localhost:4444", + SecretSource: "aws", + AwsLocalEndpoint: "http://localhost:4566", + } + + env, err := ParseRefundUserPegOutScriptInput(scriptInput, func(fd int) ([]byte, error) { + return []byte("password"), nil + }) + require.NoError(t, err) + assert.Equal(t, "regtest", env.LpsStage) + assert.Equal(t, "http://localhost:4444", env.Rsk.Endpoint) + assert.Equal(t, "aws", env.SecretSource) + assert.Equal(t, "http://localhost:4566", env.AwsLocalEndpoint) + }) +} + +func TestRefundUserPegOut(t *testing.T) { + t.Run("should execute refund user peg out successfully", func(t *testing.T) { + lbc := &mocks.LbcMock{} + quoteHash := "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc" + expectedTxHash := test.AnyHash + + // Setup mock expectations + lbc.On("RefundUserPegOut", quoteHash).Return(expectedTxHash, nil) + + txHash, err := ExecuteRefundUserPegOut(lbc, quoteHash) + require.NoError(t, err) + assert.Equal(t, expectedTxHash, txHash) + + // Verify all expectations were met + lbc.AssertExpectations(t) + }) +} diff --git a/internal/adapters/dataproviders/rootstock/bindings.go b/internal/adapters/dataproviders/rootstock/bindings.go index 6f8f35fe..404809a3 100644 --- a/internal/adapters/dataproviders/rootstock/bindings.go +++ b/internal/adapters/dataproviders/rootstock/bindings.go @@ -2,12 +2,13 @@ package rootstock import ( "context" + "math/big" + "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/rsksmart/liquidity-provider-server/internal/adapters/dataproviders/rootstock/bindings" - "math/big" ) type RpcClientBinding interface { @@ -70,6 +71,7 @@ type LbcBinding interface { ProductFeePercentage(opts *bind.CallOpts) (*big.Int, error) IsPegOutQuoteCompleted(opts *bind.CallOpts, quoteHash [32]byte) (bool, error) UpdateProvider(opts *bind.TransactOpts, _name string, _url string) (*types.Transaction, error) + RefundUserPegOut(opts *bind.TransactOpts, quoteHash [32]byte) (*types.Transaction, error) } type LbcAdapter interface { diff --git a/internal/adapters/dataproviders/rootstock/lbc.go b/internal/adapters/dataproviders/rootstock/lbc.go index 444461e0..bffc6763 100644 --- a/internal/adapters/dataproviders/rootstock/lbc.go +++ b/internal/adapters/dataproviders/rootstock/lbc.go @@ -5,6 +5,10 @@ import ( "encoding/hex" "errors" "fmt" + "math/big" + "strings" + "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" geth "github.com/ethereum/go-ethereum/core/types" @@ -15,9 +19,6 @@ import ( "github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider" "github.com/rsksmart/liquidity-provider-server/internal/entities/quote" log "github.com/sirupsen/logrus" - "math/big" - "strings" - "time" ) // registerPeginGasLimit Fixed gas limit for registerPegin function, should change only if the function does @@ -612,6 +613,26 @@ func (lbc *liquidityBridgeContractImpl) UpdateProvider(name, url string) (string return receipt.TxHash.String(), nil } +func (lbc *liquidityBridgeContractImpl) RefundUserPegOut(quoteHash string) (string, error) { + opts := &bind.TransactOpts{ + From: lbc.signer.Address(), + Signer: lbc.signer.Sign, + } + receipt, err := awaitTx(lbc.client, "RefundUserPegOut", func() (*geth.Transaction, error) { + return lbc.contract.RefundUserPegOut(opts, common.HexToHash(quoteHash)) + }) + + if err != nil { + return "", fmt.Errorf("refund user peg out error: %w", err) + } else if receipt == nil { + return "", errors.New("refund user peg out error: incomplete receipt") + } else if receipt.Status == 0 { + txHash := receipt.TxHash.String() + return txHash, fmt.Errorf("refund user peg out error: transaction reverted (%s)", txHash) + } + return receipt.TxHash.String(), nil +} + // parsePeginQuote parses a quote.PeginQuote into a bindings.QuotesPeginQuote. All BTC address fields support all address types // except for FedBtcAddress which must be a P2SH address. func parsePeginQuote(peginQuote quote.PeginQuote) (bindings.QuotesPeginQuote, error) { diff --git a/internal/entities/blockchain/lbc.go b/internal/entities/blockchain/lbc.go index 79f6112b..ab4b780c 100644 --- a/internal/entities/blockchain/lbc.go +++ b/internal/entities/blockchain/lbc.go @@ -4,10 +4,11 @@ import ( "context" "encoding/hex" "fmt" + "math/big" + "github.com/rsksmart/liquidity-provider-server/internal/entities" "github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider" "github.com/rsksmart/liquidity-provider-server/internal/entities/quote" - "math/big" ) const ( @@ -100,6 +101,7 @@ type LiquidityBridgeContract interface { GetPeginPunishmentEvents(ctx context.Context, fromBlock uint64, toBlock *uint64) ([]liquidity_provider.PunishmentEvent, error) IsPegOutQuoteCompleted(quoteHash string) (bool, error) UpdateProvider(name, url string) (string, error) + RefundUserPegOut(quoteHash string) (string, error) } type FeeCollector interface { diff --git a/test/mocks/abstract_factory_mock.go b/test/mocks/abstract_factory_mock.go index b14bd1ee..4f0048a5 100644 --- a/test/mocks/abstract_factory_mock.go +++ b/test/mocks/abstract_factory_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/bitcoin_wallet_mock.go b/test/mocks/bitcoin_wallet_mock.go index 638710b4..c004a130 100644 --- a/test/mocks/bitcoin_wallet_mock.go +++ b/test/mocks/bitcoin_wallet_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/client_adapter_mock.go b/test/mocks/client_adapter_mock.go index f29b81e2..68625e3c 100644 --- a/test/mocks/client_adapter_mock.go +++ b/test/mocks/client_adapter_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/collection_binding_mock.go b/test/mocks/collection_binding_mock.go index f6b28685..22bc0c15 100644 --- a/test/mocks/collection_binding_mock.go +++ b/test/mocks/collection_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/db_binding_mock.go b/test/mocks/db_binding_mock.go index 3e5571f5..692599f6 100644 --- a/test/mocks/db_binding_mock.go +++ b/test/mocks/db_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/db_client_binding_mock.go b/test/mocks/db_client_binding_mock.go index af5614e2..d15faf39 100644 --- a/test/mocks/db_client_binding_mock.go +++ b/test/mocks/db_client_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/default_credentials_provider_mock.go b/test/mocks/default_credentials_provider_mock.go index 57315cb7..c31ed0f3 100644 --- a/test/mocks/default_credentials_provider_mock.go +++ b/test/mocks/default_credentials_provider_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/event_iterator_adapter_mock.go b/test/mocks/event_iterator_adapter_mock.go index d023ea16..1fb1fc6d 100644 --- a/test/mocks/event_iterator_adapter_mock.go +++ b/test/mocks/event_iterator_adapter_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/http_client_mock.go b/test/mocks/http_client_mock.go index d455d764..2ad3ca63 100644 --- a/test/mocks/http_client_mock.go +++ b/test/mocks/http_client_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/lbc_adapter_mock.go b/test/mocks/lbc_adapter_mock.go index 69ec0698..47976d7e 100644 --- a/test/mocks/lbc_adapter_mock.go +++ b/test/mocks/lbc_adapter_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks @@ -1341,6 +1341,65 @@ func (_c *LbcAdapterMock_RefundPegOut_Call) RunAndReturn(run func(*bind.Transact return _c } +// RefundUserPegOut provides a mock function with given fields: opts, quoteHash +func (_m *LbcAdapterMock) RefundUserPegOut(opts *bind.TransactOpts, quoteHash [32]byte) (*types.Transaction, error) { + ret := _m.Called(opts, quoteHash) + + if len(ret) == 0 { + panic("no return value specified for RefundUserPegOut") + } + + var r0 *types.Transaction + var r1 error + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [32]byte) (*types.Transaction, error)); ok { + return rf(opts, quoteHash) + } + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [32]byte) *types.Transaction); ok { + r0 = rf(opts, quoteHash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Transaction) + } + } + + if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [32]byte) error); ok { + r1 = rf(opts, quoteHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LbcAdapterMock_RefundUserPegOut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RefundUserPegOut' +type LbcAdapterMock_RefundUserPegOut_Call struct { + *mock.Call +} + +// RefundUserPegOut is a helper method to define mock.On call +// - opts *bind.TransactOpts +// - quoteHash [32]byte +func (_e *LbcAdapterMock_Expecter) RefundUserPegOut(opts interface{}, quoteHash interface{}) *LbcAdapterMock_RefundUserPegOut_Call { + return &LbcAdapterMock_RefundUserPegOut_Call{Call: _e.mock.On("RefundUserPegOut", opts, quoteHash)} +} + +func (_c *LbcAdapterMock_RefundUserPegOut_Call) Run(run func(opts *bind.TransactOpts, quoteHash [32]byte)) *LbcAdapterMock_RefundUserPegOut_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bind.TransactOpts), args[1].([32]byte)) + }) + return _c +} + +func (_c *LbcAdapterMock_RefundUserPegOut_Call) Return(_a0 *types.Transaction, _a1 error) *LbcAdapterMock_RefundUserPegOut_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LbcAdapterMock_RefundUserPegOut_Call) RunAndReturn(run func(*bind.TransactOpts, [32]byte) (*types.Transaction, error)) *LbcAdapterMock_RefundUserPegOut_Call { + _c.Call.Return(run) + return _c +} + // Register provides a mock function with given fields: opts, _name, _apiBaseUrl, _status, _providerType func (_m *LbcAdapterMock) Register(opts *bind.TransactOpts, _name string, _apiBaseUrl string, _status bool, _providerType string) (*types.Transaction, error) { ret := _m.Called(opts, _name, _apiBaseUrl, _status, _providerType) diff --git a/test/mocks/lbc_binding_mock.go b/test/mocks/lbc_binding_mock.go index 770daa4a..9143006a 100644 --- a/test/mocks/lbc_binding_mock.go +++ b/test/mocks/lbc_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks @@ -1196,6 +1196,65 @@ func (_c *LbcBindingMock_RefundPegOut_Call) RunAndReturn(run func(*bind.Transact return _c } +// RefundUserPegOut provides a mock function with given fields: opts, quoteHash +func (_m *LbcBindingMock) RefundUserPegOut(opts *bind.TransactOpts, quoteHash [32]byte) (*types.Transaction, error) { + ret := _m.Called(opts, quoteHash) + + if len(ret) == 0 { + panic("no return value specified for RefundUserPegOut") + } + + var r0 *types.Transaction + var r1 error + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [32]byte) (*types.Transaction, error)); ok { + return rf(opts, quoteHash) + } + if rf, ok := ret.Get(0).(func(*bind.TransactOpts, [32]byte) *types.Transaction); ok { + r0 = rf(opts, quoteHash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Transaction) + } + } + + if rf, ok := ret.Get(1).(func(*bind.TransactOpts, [32]byte) error); ok { + r1 = rf(opts, quoteHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LbcBindingMock_RefundUserPegOut_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RefundUserPegOut' +type LbcBindingMock_RefundUserPegOut_Call struct { + *mock.Call +} + +// RefundUserPegOut is a helper method to define mock.On call +// - opts *bind.TransactOpts +// - quoteHash [32]byte +func (_e *LbcBindingMock_Expecter) RefundUserPegOut(opts interface{}, quoteHash interface{}) *LbcBindingMock_RefundUserPegOut_Call { + return &LbcBindingMock_RefundUserPegOut_Call{Call: _e.mock.On("RefundUserPegOut", opts, quoteHash)} +} + +func (_c *LbcBindingMock_RefundUserPegOut_Call) Run(run func(opts *bind.TransactOpts, quoteHash [32]byte)) *LbcBindingMock_RefundUserPegOut_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*bind.TransactOpts), args[1].([32]byte)) + }) + return _c +} + +func (_c *LbcBindingMock_RefundUserPegOut_Call) Return(_a0 *types.Transaction, _a1 error) *LbcBindingMock_RefundUserPegOut_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *LbcBindingMock_RefundUserPegOut_Call) RunAndReturn(run func(*bind.TransactOpts, [32]byte) (*types.Transaction, error)) *LbcBindingMock_RefundUserPegOut_Call { + _c.Call.Return(run) + return _c +} + // Register provides a mock function with given fields: opts, _name, _apiBaseUrl, _status, _providerType func (_m *LbcBindingMock) Register(opts *bind.TransactOpts, _name string, _apiBaseUrl string, _status bool, _providerType string) (*types.Transaction, error) { ret := _m.Called(opts, _name, _apiBaseUrl, _status, _providerType) diff --git a/test/mocks/lbc_mock.go b/test/mocks/lbc_mock.go index 935fa92a..f76620ca 100644 --- a/test/mocks/lbc_mock.go +++ b/test/mocks/lbc_mock.go @@ -2,6 +2,7 @@ package mocks import ( "context" + "github.com/rsksmart/liquidity-provider-server/internal/entities" "github.com/rsksmart/liquidity-provider-server/internal/entities/blockchain" "github.com/rsksmart/liquidity-provider-server/internal/entities/liquidity_provider" @@ -156,3 +157,8 @@ func (m *LbcMock) UpdateProvider(name, url string) (string, error) { args := m.Called(name, url) return args.String(0), args.Error(1) } + +func (m *LbcMock) RefundUserPegOut(quoteHash string) (string, error) { + args := m.Called(quoteHash) + return args.String(0), args.Error(1) +} diff --git a/test/mocks/liquidity_provider_repository_mock.go b/test/mocks/liquidity_provider_repository_mock.go index f9289b9e..f601d208 100644 --- a/test/mocks/liquidity_provider_repository_mock.go +++ b/test/mocks/liquidity_provider_repository_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/pegin_quote_repository_mock.go b/test/mocks/pegin_quote_repository_mock.go index 05da44b4..7493d13e 100644 --- a/test/mocks/pegin_quote_repository_mock.go +++ b/test/mocks/pegin_quote_repository_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/pegout_quote_repository_mock.go b/test/mocks/pegout_quote_repository_mock.go index 9a92a075..efc13096 100644 --- a/test/mocks/pegout_quote_repository_mock.go +++ b/test/mocks/pegout_quote_repository_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/rootstock_rpc_server_mock.go b/test/mocks/rootstock_rpc_server_mock.go index 496be6d5..19a4bf30 100644 --- a/test/mocks/rootstock_rpc_server_mock.go +++ b/test/mocks/rootstock_rpc_server_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/rpc_client_binding_mock.go b/test/mocks/rpc_client_binding_mock.go index 51009b16..04a3105f 100644 --- a/test/mocks/rpc_client_binding_mock.go +++ b/test/mocks/rpc_client_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/rpc_client_mock.go b/test/mocks/rpc_client_mock.go index 5173a628..6547e5a5 100644 --- a/test/mocks/rpc_client_mock.go +++ b/test/mocks/rpc_client_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/rsk_bridge_binding_mock.go b/test/mocks/rsk_bridge_binding_mock.go index a547f0e0..110f34cb 100644 --- a/test/mocks/rsk_bridge_binding_mock.go +++ b/test/mocks/rsk_bridge_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/rsk_signer_wallet_mock.go b/test/mocks/rsk_signer_wallet_mock.go index a6f59ea3..9ab828da 100644 --- a/test/mocks/rsk_signer_wallet_mock.go +++ b/test/mocks/rsk_signer_wallet_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/ses_client_mock.go b/test/mocks/ses_client_mock.go index cf72e605..39fd7f05 100644 --- a/test/mocks/ses_client_mock.go +++ b/test/mocks/ses_client_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/session_binding_mock.go b/test/mocks/session_binding_mock.go index 172197a9..7de46faf 100644 --- a/test/mocks/session_binding_mock.go +++ b/test/mocks/session_binding_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/store_mock.go b/test/mocks/store_mock.go index 685bc881..b0c1ac36 100644 --- a/test/mocks/store_mock.go +++ b/test/mocks/store_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/ticker_mock.go b/test/mocks/ticker_mock.go index 5ef8acf5..9468d69c 100644 --- a/test/mocks/ticker_mock.go +++ b/test/mocks/ticker_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/transaction_signer_mock.go b/test/mocks/transaction_signer_mock.go index ef5a3adb..7cf309b3 100644 --- a/test/mocks/transaction_signer_mock.go +++ b/test/mocks/transaction_signer_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks diff --git a/test/mocks/use_case_registry_mock.go b/test/mocks/use_case_registry_mock.go index bb4237b6..404b4dba 100644 --- a/test/mocks/use_case_registry_mock.go +++ b/test/mocks/use_case_registry_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.46.3. DO NOT EDIT. +// Code generated by mockery v2.48.0. DO NOT EDIT. package mocks From cb6d5ac23877ea9e8ce6ccb0bc2b5b905b9180b2 Mon Sep 17 00:00:00 2001 From: AndresQuijano Date: Thu, 21 Nov 2024 16:10:46 +0000 Subject: [PATCH 2/5] fix: address sonarcloud issues of duplicate code --- .../refund_user_pegout_test.go | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go index ad0c6f5e..9b6ee50d 100644 --- a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go +++ b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go @@ -11,6 +11,14 @@ import ( "golang.org/x/term" ) +const ( + testRskEndpoint = "http://localhost:4444" + testQuoteHash = "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc" + testAwsLocalEndpoint = "http://localhost:4566" + testNetwork = "regtest" + testKeystoreFile = "./keystore.json" +) + func TestReadRefundUserPegOutScriptInput(t *testing.T) { t.Run("should set flag values", func(t *testing.T) { // Reset flags before test @@ -21,19 +29,19 @@ func TestReadRefundUserPegOutScriptInput(t *testing.T) { // Set test values err := flag.CommandLine.Parse([]string{ - "-network", "regtest", - "-quote-hash", "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc", - "-rsk-endpoint", "http://localhost:4444", + "-network", testNetwork, + "-quote-hash", testQuoteHash, + "-rsk-endpoint", testRskEndpoint, "-secret-src", "env", - "-keystore-file", "./keystore.json", + "-keystore-file", testKeystoreFile, }) require.NoError(t, err) - assert.Equal(t, "regtest", scriptInput.Network) - assert.Equal(t, "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc", scriptInput.QuoteHashBytes) - assert.Equal(t, "http://localhost:4444", scriptInput.RskEndpoint) + assert.Equal(t, testNetwork, scriptInput.Network) + assert.Equal(t, testQuoteHash, scriptInput.QuoteHashBytes) + assert.Equal(t, testRskEndpoint, scriptInput.RskEndpoint) assert.Equal(t, "env", scriptInput.SecretSource) - assert.Equal(t, "./keystore.json", scriptInput.KeystoreFile) + assert.Equal(t, testKeystoreFile, scriptInput.KeystoreFile) }) } @@ -53,34 +61,33 @@ func TestParseRefundUserPegOutScriptInput(t *testing.T) { t.Run("should parse valid input", func(t *testing.T) { scriptInput := &RefundUserPegOutScriptInput{ - Network: "regtest", - QuoteHashBytes: "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc", - RskEndpoint: "http://localhost:4444", + Network: testNetwork, + QuoteHashBytes: testQuoteHash, + RskEndpoint: testRskEndpoint, SecretSource: "aws", - AwsLocalEndpoint: "http://localhost:4566", + AwsLocalEndpoint: testAwsLocalEndpoint, } env, err := ParseRefundUserPegOutScriptInput(scriptInput, func(fd int) ([]byte, error) { return []byte("password"), nil }) require.NoError(t, err) - assert.Equal(t, "regtest", env.LpsStage) - assert.Equal(t, "http://localhost:4444", env.Rsk.Endpoint) + assert.Equal(t, testNetwork, env.LpsStage) + assert.Equal(t, testRskEndpoint, env.Rsk.Endpoint) assert.Equal(t, "aws", env.SecretSource) - assert.Equal(t, "http://localhost:4566", env.AwsLocalEndpoint) + assert.Equal(t, testAwsLocalEndpoint, env.AwsLocalEndpoint) }) } func TestRefundUserPegOut(t *testing.T) { t.Run("should execute refund user peg out successfully", func(t *testing.T) { lbc := &mocks.LbcMock{} - quoteHash := "d93f58c82100a6cee4f19ac505c11d51b52cafe220f7f1944b70496f33d277fc" expectedTxHash := test.AnyHash // Setup mock expectations - lbc.On("RefundUserPegOut", quoteHash).Return(expectedTxHash, nil) + lbc.On("RefundUserPegOut", testQuoteHash).Return(expectedTxHash, nil) - txHash, err := ExecuteRefundUserPegOut(lbc, quoteHash) + txHash, err := ExecuteRefundUserPegOut(lbc, testQuoteHash) require.NoError(t, err) assert.Equal(t, expectedTxHash, txHash) From 1a6b5b9991689cd97e6bb2c15d444c60aeabcaf6 Mon Sep 17 00:00:00 2001 From: AndresQuijano Date: Thu, 21 Nov 2024 17:21:19 +0000 Subject: [PATCH 3/5] feat: refactor refund user pegout script to receive a parse function - add documentation - modify Makefile --- Makefile | 1 + README.md | 1 + cmd/utils/refund_user_pegout/refund_user_pegout.go | 6 +++--- cmd/utils/refund_user_pegout/refund_user_pegout_test.go | 6 ++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 56004fad..9c3fac7d 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,7 @@ utils: download mkdir -p utils CGO_ENABLED=0 go build -v -o ./utils/update_provider_url ./cmd/utils/update_provider_url/update_provider_url.go CGO_ENABLED=0 go build -v -o ./utils/register_pegin ./cmd/utils/register_pegin/register_pegin.go + CGO_ENABLED=0 go build -v -o ./utils/refund_user_pegout ./cmd/utils/refund_user_pegout/refund_user_pegout.go utils-docker: rm -rf utils diff --git a/README.md b/README.md index 780bddae..2bfe8cd8 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ with `go run` or build them with `make utils`. You can run the scripts with the - **update_provider_url**: updates the URL of a liquidity provider provided when the discovery function of the Liquidity Bridge Contract is executed. - **register_pegin**: register a PegIn transaction within the Liquidity Bridge Contract. Most times, this script is only required to execute refunds on special cases. This script requires an input file whose structure can be found [the input-example.json](cmd/utils/register_pegin/input-example.json) file. +- **refund_user_pegout**: executes a refund for a user's peg-out operation through the Liquidity Bridge Contract. This is used when a peg-out operation needs to be refunded back to the user's RSK address. The script requires the quote hash of the operation to refund. ### More information If you're looking forward to integrate with Flyover Protocol then you can check the [Flyover SDK repository](https://github.com/rsksmart/unified-bridges-sdk/tree/main/packages/flyover-sdk). diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout.go b/cmd/utils/refund_user_pegout/refund_user_pegout.go index 83216a27..59454e22 100644 --- a/cmd/utils/refund_user_pegout/refund_user_pegout.go +++ b/cmd/utils/refund_user_pegout/refund_user_pegout.go @@ -33,7 +33,7 @@ type PasswordReader = func(int) ([]byte, error) func main() { scriptInput := new(RefundUserPegOutScriptInput) ReadRefundUserPegOutScriptInput(scriptInput) - env, err := ParseRefundUserPegOutScriptInput(scriptInput, term.ReadPassword) + env, err := ParseRefundUserPegOutScriptInput(flag.Parse, scriptInput, term.ReadPassword) if err != nil { scripts.ExitWithError(2, "Error reading input", err) } @@ -65,9 +65,9 @@ func ReadRefundUserPegOutScriptInput(scriptInput *RefundUserPegOutScriptInput) { flag.StringVar(&scriptInput.EncryptedJsonPasswordSecret, "password-secret", "", "Name of the secret storing the keystore password. Only required if the secret source is aws") } -func ParseRefundUserPegOutScriptInput(scriptInput *RefundUserPegOutScriptInput, pwdReader PasswordReader) (environment.Environment, error) { +func ParseRefundUserPegOutScriptInput(parse scripts.ParseFunc, scriptInput *RefundUserPegOutScriptInput, pwdReader PasswordReader) (environment.Environment, error) { var env environment.Environment - flag.Parse() + parse() validate := validator.New(validator.WithRequiredStructEnabled()) err := validate.Struct(scriptInput) if err != nil { diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go index 9b6ee50d..9cc2713c 100644 --- a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go +++ b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go @@ -46,6 +46,8 @@ func TestReadRefundUserPegOutScriptInput(t *testing.T) { } func TestParseRefundUserPegOutScriptInput(t *testing.T) { + parse := func() {} + t.Run("should validate required fields", func(t *testing.T) { scriptInput := &RefundUserPegOutScriptInput{ Network: "", @@ -54,7 +56,7 @@ func TestParseRefundUserPegOutScriptInput(t *testing.T) { SecretSource: "", } - _, err := ParseRefundUserPegOutScriptInput(scriptInput, term.ReadPassword) + _, err := ParseRefundUserPegOutScriptInput(parse, scriptInput, term.ReadPassword) require.Error(t, err) assert.Contains(t, err.Error(), "invalid input") }) @@ -68,7 +70,7 @@ func TestParseRefundUserPegOutScriptInput(t *testing.T) { AwsLocalEndpoint: testAwsLocalEndpoint, } - env, err := ParseRefundUserPegOutScriptInput(scriptInput, func(fd int) ([]byte, error) { + env, err := ParseRefundUserPegOutScriptInput(parse, scriptInput, func(fd int) ([]byte, error) { return []byte("password"), nil }) require.NoError(t, err) From def51c3b8bac2212ec729e6b431c921988d53a1c Mon Sep 17 00:00:00 2001 From: AndresQuijano Date: Fri, 22 Nov 2024 11:16:10 +0000 Subject: [PATCH 4/5] feat: add validation for quote hash in RefundUserPegOut - add tests --- .../refund_user_pegout_test.go | 2 + .../adapters/dataproviders/rootstock/lbc.go | 9 +++ .../dataproviders/rootstock/lbc_test.go | 58 ++++++++++++++++++- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go index 9cc2713c..b66ef3e4 100644 --- a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go +++ b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go @@ -46,6 +46,8 @@ func TestReadRefundUserPegOutScriptInput(t *testing.T) { } func TestParseRefundUserPegOutScriptInput(t *testing.T) { + // parse is a no-op function used as a placeholder in tests since the actual parsing + // functionality is not relevant for these test cases parse := func() {} t.Run("should validate required fields", func(t *testing.T) { diff --git a/internal/adapters/dataproviders/rootstock/lbc.go b/internal/adapters/dataproviders/rootstock/lbc.go index bffc6763..aa3051c3 100644 --- a/internal/adapters/dataproviders/rootstock/lbc.go +++ b/internal/adapters/dataproviders/rootstock/lbc.go @@ -614,6 +614,15 @@ func (lbc *liquidityBridgeContractImpl) UpdateProvider(name, url string) (string } func (lbc *liquidityBridgeContractImpl) RefundUserPegOut(quoteHash string) (string, error) { + // Validate the hash format + hashBytesSlice, err := hex.DecodeString(quoteHash) + if err != nil { + return "", fmt.Errorf("invalid quote hash format: %w", err) + } + if len(hashBytesSlice) != 32 { + return "", errors.New("quote hash must be 32 bytes long") + } + opts := &bind.TransactOpts{ From: lbc.signer.Address(), Signer: lbc.signer.Sign, diff --git a/internal/adapters/dataproviders/rootstock/lbc_test.go b/internal/adapters/dataproviders/rootstock/lbc_test.go index 89a3ff52..22e00460 100644 --- a/internal/adapters/dataproviders/rootstock/lbc_test.go +++ b/internal/adapters/dataproviders/rootstock/lbc_test.go @@ -5,6 +5,11 @@ import ( "context" "encoding/hex" "errors" + "math/big" + "strings" + "testing" + "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" geth "github.com/ethereum/go-ethereum/core/types" @@ -19,9 +24,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "math/big" - "testing" - "time" ) const ( @@ -918,6 +920,56 @@ func TestLiquidityBridgeContractImpl_RegisterPegin_ErrorHandling(t *testing.T) { }) } +func TestLiquidityBridgeContractImpl_RefundUserPegOut(t *testing.T) { + lbcMock := &mocks.LbcAdapterMock{} + signer := &mocks.TransactionSignerMock{} + client := &mocks.RpcClientBindingMock{} + lbc := rootstock.NewLiquidityBridgeContractImpl( + rootstock.NewRskClient(client), + test.AnyAddress, + lbcMock, + signer, + rootstock.RetryParams{}, + ) + + t.Run("should fail with invalid hash format", func(t *testing.T) { + result, err := lbc.RefundUserPegOut("invalid hash") + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid quote hash format") + assert.Empty(t, result) + }) + + t.Run("should fail with invalid hash length", func(t *testing.T) { + result, err := lbc.RefundUserPegOut("ab") + require.Error(t, err) + assert.Contains(t, err.Error(), "quote hash must be 32 bytes long") + assert.Empty(t, result) + }) + + t.Run("should fail if transaction fails", func(t *testing.T) { + validHash := strings.Repeat("aa", 32) + tx := prepareTxMocks(client, signer, false) + lbcMock.On("RefundUserPegOut", mock.Anything, mock.Anything).Return(tx, assert.AnError).Once() + + result, err := lbc.RefundUserPegOut(validHash) + require.Error(t, err) + assert.Contains(t, err.Error(), "refund user peg out error") + assert.Empty(t, result) + }) + + t.Run("should succeed", func(t *testing.T) { + validHash := strings.Repeat("aa", 32) + tx := prepareTxMocks(client, signer, true) + lbcMock.On("RefundUserPegOut", mock.Anything, mock.Anything).Return(tx, nil).Once() + + result, err := lbc.RefundUserPegOut(validHash) + require.NoError(t, err) + assert.Equal(t, tx.Hash().String(), result) + + lbcMock.AssertExpectations(t) + }) +} + // nolint:funlen func TestLiquidityBridgeContractImpl_RefundPegout(t *testing.T) { var gasLimit uint64 = 500 From f166d536482c1c08dcfba546b8a5c6c2fae4e910 Mon Sep 17 00:00:00 2001 From: AndresQuijano Date: Fri, 22 Nov 2024 11:24:39 +0000 Subject: [PATCH 5/5] fix: sonarcloud issues --- cmd/utils/refund_user_pegout/refund_user_pegout_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go index b66ef3e4..4194bac5 100644 --- a/cmd/utils/refund_user_pegout/refund_user_pegout_test.go +++ b/cmd/utils/refund_user_pegout/refund_user_pegout_test.go @@ -46,9 +46,10 @@ func TestReadRefundUserPegOutScriptInput(t *testing.T) { } func TestParseRefundUserPegOutScriptInput(t *testing.T) { - // parse is a no-op function used as a placeholder in tests since the actual parsing - // functionality is not relevant for these test cases - parse := func() {} + + parse := func() { // parse is a no-op function used as a placeholder in tests since the actual parsing + // functionality is not relevant for these test cases + } t.Run("should validate required fields", func(t *testing.T) { scriptInput := &RefundUserPegOutScriptInput{