Files
atomic-swap/daemon/manual_tx_test.go
2023-05-02 23:12:45 -05:00

124 lines
3.5 KiB
Go

// Copyright 2023 The AthanorLabs/atomic-swap Authors
// SPDX-License-Identifier: LGPL-3.0-only
package daemon
import (
"fmt"
"sync"
"testing"
"time"
"github.com/athanorlabs/atomic-swap/coins"
"github.com/athanorlabs/atomic-swap/common"
"github.com/athanorlabs/atomic-swap/common/types"
"github.com/athanorlabs/atomic-swap/ethereum/block"
"github.com/athanorlabs/atomic-swap/monero"
"github.com/athanorlabs/atomic-swap/rpcclient"
"github.com/athanorlabs/atomic-swap/rpcclient/wsclient"
"github.com/athanorlabs/atomic-swap/tests"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Test if Alice is able to call the Refund() RPC API (used by swapcli refund) immediately after locking her ETH.
func TestRunSwapDaemon_ManualRefund(t *testing.T) {
minXMR := coins.StrToDecimal("1")
maxXMR := minXMR
exRate := coins.StrToExchangeRate("0.1")
providesAmt, err := exRate.ToETH(minXMR)
require.NoError(t, err)
bobEthKey, err := crypto.GenerateKey()
require.NoError(t, err)
bobConf := CreateTestConf(t, bobEthKey)
monero.MineMinXMRBalance(t, bobConf.MoneroClient, coins.MoneroToPiconero(maxXMR))
aliceConf := CreateTestConf(t, tests.GetTakerTestKey(t))
timeout := 7 * time.Minute
ctx, _ := LaunchDaemons(t, timeout, bobConf, aliceConf)
bc, err := wsclient.NewWsClient(ctx, fmt.Sprintf("ws://127.0.0.1:%d/ws", bobConf.RPCPort))
require.NoError(t, err)
ac, err := wsclient.NewWsClient(ctx, fmt.Sprintf("ws://127.0.0.1:%d/ws", aliceConf.RPCPort))
require.NoError(t, err)
acHTTP := rpcclient.NewClient(ctx, fmt.Sprintf("http://127.0.0.1:%d", aliceConf.RPCPort))
useRelayer := false
makeResp, bobStatusCh, err := bc.MakeOfferAndSubscribe(minXMR, maxXMR, exRate, types.EthAssetETH, useRelayer)
require.NoError(t, err)
aliceStatusCh, err := ac.TakeOfferAndSubscribe(makeResp.PeerID, makeResp.OfferID, providesAmt)
require.NoError(t, err)
var statusWG sync.WaitGroup
statusWG.Add(2)
go func() {
defer statusWG.Done()
for {
select {
case status := <-aliceStatusCh:
t.Log("> Alice got status:", status)
if !status.IsOngoing() {
assert.Equal(t, types.CompletedRefund.String(), status.String())
return
}
if status == types.ETHLocked {
// wait for eth lock to get included
time.Sleep(time.Second)
// call refund
t.Log("> Alice calling refund")
refundResp, err := acHTTP.Refund(makeResp.OfferID)
require.NoError(t, err)
ec, err := ethclient.Dial(common.DefaultGanacheEndpoint)
require.NoError(t, err)
t.Log("> Alice got refund response tx:", refundResp.TxHash)
receipt, err := block.WaitForReceipt(ctx, ec, refundResp.TxHash)
require.NoError(t, err)
assert.Equal(t, uint64(1), receipt.Status)
// manually trigger exit, since the xmrtaker doesn't watch for Refunded events.
status, err := acHTTP.Cancel(makeResp.OfferID)
require.NoError(t, err)
assert.Equal(t, types.CompletedRefund.String(), status.String())
return
}
case <-ctx.Done():
t.Errorf("Alice's context cancelled before she completed the swap")
return
}
}
}()
go func() {
defer statusWG.Done()
for {
select {
case status := <-bobStatusCh:
t.Log("> Bob got status:", status)
if !status.IsOngoing() {
assert.Equal(t, types.CompletedRefund.String(), status.String())
return
}
case <-ctx.Done():
t.Errorf("Bob's context cancelled before he completed the swap")
return
}
}
}()
statusWG.Wait()
if t.Failed() {
return
}
}