diff --git a/protocol/xmrtaker/errors.go b/protocol/xmrtaker/errors.go index 5c5d82a1..a07d53ca 100644 --- a/protocol/xmrtaker/errors.go +++ b/protocol/xmrtaker/errors.go @@ -52,32 +52,36 @@ func errContractAddrMismatch(addr string) error { } type errAmountProvidedTooLow struct { - providedAmtETH *apd.Decimal + providedAmtETH coins.EthAssetAmount providedAmtAsXMR *apd.Decimal offerMinAmtXMR *apd.Decimal exchangeRate *coins.ExchangeRate } func (e errAmountProvidedTooLow) Error() string { - return fmt.Sprintf("provided ETH converted to XMR is under offer min of %s XMR (%s ETH / %s = %s)", + return fmt.Sprintf("provided %s converted to XMR is under offer min of %s XMR (%s %s / %s = %s)", + e.providedAmtETH.StdSymbol(), e.offerMinAmtXMR.Text('f'), - e.providedAmtETH.Text('f'), + e.providedAmtETH.AsStdString(), + e.providedAmtETH.StdSymbol(), e.exchangeRate, e.providedAmtAsXMR.Text('f'), ) } type errAmountProvidedTooHigh struct { - providedAmtETH *apd.Decimal + providedAmtETH coins.EthAssetAmount providedAmtAsXMR *apd.Decimal offerMaxAmtXMR *apd.Decimal exchangeRate *coins.ExchangeRate } func (e errAmountProvidedTooHigh) Error() string { - return fmt.Sprintf("provided ETH converted to XMR is over offer max of %s XMR (%s ETH / %s = %s XMR)", + return fmt.Sprintf("provided %s converted to XMR is over offer max of %s XMR (%s %s / %s = %s XMR)", + e.providedAmtETH.StdSymbol(), e.offerMaxAmtXMR.Text('f'), - e.providedAmtETH.Text('f'), + e.providedAmtETH.AsStdString(), + e.providedAmtETH.StdSymbol(), e.exchangeRate, e.providedAmtAsXMR.Text('f'), ) diff --git a/protocol/xmrtaker/net.go b/protocol/xmrtaker/net.go index 230f99cf..dba95ebc 100644 --- a/protocol/xmrtaker/net.go +++ b/protocol/xmrtaker/net.go @@ -51,7 +51,7 @@ func (inst *Instance) InitiateProtocol( if providesAmtAsXMR.Cmp(offer.MinAmount) < 0 { return nil, &errAmountProvidedTooLow{ - providedAmtETH: providesAmount, + providedAmtETH: providedAssetAmount, providedAmtAsXMR: providesAmtAsXMR, offerMinAmtXMR: offer.MinAmount, exchangeRate: offer.ExchangeRate, @@ -60,7 +60,7 @@ func (inst *Instance) InitiateProtocol( if providesAmtAsXMR.Cmp(offer.MaxAmount) > 0 { return nil, &errAmountProvidedTooHigh{ - providedAmtETH: providesAmount, + providedAmtETH: providedAssetAmount, providedAmtAsXMR: providesAmtAsXMR, offerMaxAmtXMR: offer.MaxAmount, exchangeRate: offer.ExchangeRate, diff --git a/protocol/xmrtaker/net_test.go b/protocol/xmrtaker/net_test.go index f7d9a005..53d52195 100644 --- a/protocol/xmrtaker/net_test.go +++ b/protocol/xmrtaker/net_test.go @@ -13,10 +13,7 @@ import ( "github.com/athanorlabs/atomic-swap/coins" "github.com/athanorlabs/atomic-swap/common" "github.com/athanorlabs/atomic-swap/common/types" -) - -var ( - testExchangeRate = coins.StrToExchangeRate("0.08") + contracts "github.com/athanorlabs/atomic-swap/ethereum" ) func newTestXMRTaker(t *testing.T) *Instance { @@ -34,59 +31,110 @@ func newTestXMRTaker(t *testing.T) *Instance { func initiate( xmrtaker *Instance, providesAmount *apd.Decimal, + providesAsset types.EthAsset, minAmount *apd.Decimal, maxAmount *apd.Decimal, + exchangeRate *coins.ExchangeRate, ) (*types.Offer, common.SwapState, error) { offer := types.NewOffer( coins.ProvidesETH, minAmount, maxAmount, - testExchangeRate, - types.EthAssetETH, + exchangeRate, + providesAsset, ) s, err := xmrtaker.InitiateProtocol(testPeerID, providesAmount, offer) return offer, s, err } -func TestXMRTaker_InitiateProtocol(t *testing.T) { +func TestXMRTaker_InitiateProtocol_ETH(t *testing.T) { a := newTestXMRTaker(t) min := coins.StrToDecimal("0.1") max := coins.StrToDecimal("1") + exRate := coins.StrToExchangeRate("0.08") + asset := types.EthAssetETH // Provided between minAmount and maxAmount (0.05 ETH / 0.08 = 0.625 XMR) - offer, s, err := initiate(a, coins.StrToDecimal("0.05"), min, max) + offer, s, err := initiate(a, coins.StrToDecimal("0.05"), asset, min, max, exRate) require.NoError(t, err) require.Equal(t, a.swapStates[offer.ID], s) // Exact max is in range (0.08 ETH / 0.08 = 1 XMR) - offer, s, err = initiate(a, coins.StrToDecimal("0.08"), min, max) + offer, s, err = initiate(a, coins.StrToDecimal("0.08"), asset, min, max, exRate) require.NoError(t, err) require.Equal(t, a.swapStates[offer.ID], s) // Exact min is in range (0.008 ETH / 0.08 = 0.1 XMR) - offer, s, err = initiate(a, coins.StrToDecimal("0.008"), min, max) + offer, s, err = initiate(a, coins.StrToDecimal("0.008"), asset, min, max, exRate) require.NoError(t, err) require.Equal(t, a.swapStates[offer.ID], s) // Provided with too many decimals - _, s, err = initiate(a, apd.New(1, -50), min, max) // 10^-50 + _, s, err = initiate(a, apd.New(1, -50), asset, min, max, exRate) // 10^-50 require.ErrorContains(t, err, `"providesAmount" has too many decimal points; found=50 max=18`) require.Equal(t, nil, s) // Provided with a negative number - _, s, err = initiate(a, coins.StrToDecimal("-1"), min, max) + _, s, err = initiate(a, coins.StrToDecimal("-1"), asset, min, max, exRate) require.ErrorContains(t, err, `"providesAmount" cannot be negative`) require.Equal(t, nil, s) // Provided over maxAmount (0.09 ETH / 0.08 = 1.125 XMR) - _, s, err = initiate(a, coins.StrToDecimal("0.09"), min, max) + _, s, err = initiate(a, coins.StrToDecimal("0.09"), asset, min, max, exRate) expected := `provided ETH converted to XMR is over offer max of 1 XMR (0.09 ETH / 0.08 = 1.125 XMR)` require.ErrorContains(t, err, expected) require.Equal(t, nil, s) // Provided under minAmount (0.00079 ETH / 0.08 = 0.009875 XMR) - _, s, err = initiate(a, coins.StrToDecimal("0.00079"), min, max) + _, s, err = initiate(a, coins.StrToDecimal("0.00079"), asset, min, max, exRate) expected = `provided ETH converted to XMR is under offer min of 0.1 XMR (0.00079 ETH / 0.08 = 0.009875)` require.ErrorContains(t, err, expected) require.Equal(t, nil, s) } + +func TestXMRTaker_InitiateProtocol_token(t *testing.T) { + a := newTestXMRTaker(t) + min := coins.StrToDecimal("1") + max := coins.StrToDecimal("2") + ec := a.backend.ETHClient() + token := contracts.GetMockTether(t, ec.Raw(), ec.PrivateKey()) + asset := types.EthAsset(token.Address) + exRate := coins.StrToExchangeRate("160") + + // Provided between minAmount and maxAmount (200 USDT / 160 = 1.25 XMR) + offer, s, err := initiate(a, coins.StrToDecimal("200"), asset, min, max, exRate) + require.NoError(t, err) + require.Equal(t, a.swapStates[offer.ID], s) + + // Exact max is in range (320 USDT / 160 = 2 XMR) + offer, s, err = initiate(a, coins.StrToDecimal("320"), asset, min, max, exRate) + require.NoError(t, err) + require.Equal(t, a.swapStates[offer.ID], s) + + // Exact min is in range (160 USDT / 160 = 1 XMR) + offer, s, err = initiate(a, coins.StrToDecimal("160"), asset, min, max, exRate) + require.NoError(t, err) + require.Equal(t, a.swapStates[offer.ID], s) + + // Provided with too many decimals + _, s, err = initiate(a, apd.New(1, -7), asset, min, max, exRate) // 10^-7 + require.ErrorContains(t, err, `"providesAmount" has too many decimal points; found=7 max=6`) + require.Equal(t, nil, s) + + // Provided with a negative number + _, s, err = initiate(a, coins.StrToDecimal("-1"), asset, min, max, exRate) + require.ErrorContains(t, err, `"providesAmount" cannot be negative`) + require.Equal(t, nil, s) + + // Provided over maxAmount (320.5 USDT / 160 = 2.003125 XMR) + _, s, err = initiate(a, coins.StrToDecimal("320.5"), asset, min, max, exRate) + expected := `provided "USDT" converted to XMR is over offer max of 2 XMR (320.5 "USDT" / 160 = 2.003125 XMR)` + require.ErrorContains(t, err, expected) + require.Equal(t, nil, s) + + // Provided under minAmount (159.98 USDT / 160 = 0.999875 XMR) + _, s, err = initiate(a, coins.StrToDecimal("159.98"), asset, min, max, exRate) + expected = `provided "USDT" converted to XMR is under offer min of 1 XMR (159.98 "USDT" / 160 = 0.999875)` + require.ErrorContains(t, err, expected) + require.Equal(t, nil, s) +} diff --git a/rpcclient/ws_methods.go b/rpcclient/ws_methods.go index bf6d1af7..73518c22 100644 --- a/rpcclient/ws_methods.go +++ b/rpcclient/ws_methods.go @@ -195,7 +195,7 @@ func (c *Client) readTakeOfferResponse(conn *websocket.Conn) (types.Status, erro } if resp.Error != nil { - return 0, fmt.Errorf("websocket server returned error: %w", resp.Error) + return 0, fmt.Errorf("%s error: %w", rpctypes.SubscribeTakeOffer, resp.Error) } log.Debugf("received message over websockets: %s", message) @@ -263,7 +263,7 @@ func (c *Client) MakeOfferAndSubscribe( if resp.Error != nil { _ = conn.Close() - return nil, nil, fmt.Errorf("websocket server returned error: %w", resp.Error) + return nil, nil, fmt.Errorf("%s error: %w", req.Method, resp.Error) } // read synchronous response (offer ID)