mirror of
https://github.com/AthanorLabs/atomic-swap.git
synced 2026-01-08 21:58:07 -05:00
time index shift (#450)
This commit is contained in:
@@ -292,7 +292,7 @@ func cliApp() *cli.App {
|
||||
},
|
||||
{
|
||||
Name: "set-swap-timeout",
|
||||
Usage: "Set the duration between swap initiation and t0 and t0 and t1, in seconds",
|
||||
Usage: "Set the duration between swap initiation and t1 and t1 and t2, in seconds",
|
||||
Action: runSetSwapTimeout,
|
||||
Flags: []cli.Flag{
|
||||
&cli.UintFlag{
|
||||
@@ -311,7 +311,7 @@ func cliApp() *cli.App {
|
||||
},
|
||||
{
|
||||
Name: "get-swap-timeout",
|
||||
Usage: "Get the duration between swap initiation and t0 and t0 and t1, in seconds",
|
||||
Usage: "Get the duration between swap initiation and t1 and t1 and t2, in seconds",
|
||||
Action: runGetSwapTimeout,
|
||||
Flags: []cli.Flag{
|
||||
swapdPortFlag,
|
||||
@@ -799,9 +799,9 @@ func runGetOngoingSwap(ctx *cli.Context) error {
|
||||
fmt.Printf("Exchange Rate: %s ETH/XMR\n", info.ExchangeRate)
|
||||
fmt.Printf("Status: %s\n", info.Status)
|
||||
fmt.Printf("Time status was last updated: %s\n", info.LastStatusUpdateTime.Format(common.TimeFmtSecs))
|
||||
if info.Timeout0 != nil && info.Timeout1 != nil {
|
||||
fmt.Printf("First timeout: %s\n", info.Timeout0.Format(common.TimeFmtSecs))
|
||||
fmt.Printf("Second timeout: %s\n", info.Timeout1.Format(common.TimeFmtSecs))
|
||||
if info.Timeout1 != nil && info.Timeout2 != nil {
|
||||
fmt.Printf("First timeout: %s\n", info.Timeout1.Format(common.TimeFmtSecs))
|
||||
fmt.Printf("Second timeout: %s\n", info.Timeout2.Format(common.TimeFmtSecs))
|
||||
}
|
||||
fmt.Printf("Estimated time to completion: %s\n", info.EstimatedTimeToCompletion)
|
||||
}
|
||||
@@ -1065,8 +1065,8 @@ func runGetContractSwapInfo(ctx *cli.Context) error {
|
||||
fmt.Printf("\tClaimer: %s\n", resp.Swap.Claimer)
|
||||
fmt.Printf("\tPubKeyClaim: %x\n", resp.Swap.PubKeyClaim)
|
||||
fmt.Printf("\tPubKeyRefund: %x\n", resp.Swap.PubKeyRefund)
|
||||
fmt.Printf("\tTimeout0: %s\n", resp.Swap.Timeout0)
|
||||
fmt.Printf("\tTimeout1: %s\n", resp.Swap.Timeout1)
|
||||
fmt.Printf("\tTimeout2: %s\n", resp.Swap.Timeout2)
|
||||
fmt.Printf("\tAsset: %s\n", resp.Swap.Asset)
|
||||
fmt.Printf("\tValue: %s\n", resp.Swap.Value)
|
||||
fmt.Printf("\tNonce: %s\n", resp.Swap.Nonce)
|
||||
|
||||
@@ -103,7 +103,7 @@ func StagenetConfig() *Config {
|
||||
Port: 38081,
|
||||
},
|
||||
},
|
||||
SwapCreatorAddr: ethcommon.HexToAddress("0x90119FA88abE871B3e26DF3a57C29A450f006065"),
|
||||
SwapCreatorAddr: ethcommon.HexToAddress("0xbf2B7a6dCE5598Cf002B3507a8D62cf2C35cE5c6"),
|
||||
Bootnodes: []string{
|
||||
"/ip4/134.122.115.208/tcp/9900/p2p/12D3KooWDqCzbjexHEa8Rut7bzxHFpRMZyDRW1L6TGkL1KY24JH5",
|
||||
"/ip4/143.198.123.27/tcp/9900/p2p/12D3KooWSc4yFkPWBFmPToTMbhChH3FAgGH96DNzSg5fio1pQYoN",
|
||||
|
||||
@@ -188,7 +188,7 @@ func TestRunSwapDaemon_SwapBobHasNoEth_AliceRelaysClaim(t *testing.T) {
|
||||
// Tests the scenario where Bob has no ETH, he can't find an advertised relayer,
|
||||
// and Alice does not have enough ETH to relay his claim. The end result should
|
||||
// be a refund. Note that this test has a long pause, as the refund cannot
|
||||
// happen until T1 expires.
|
||||
// happen until T2 expires.
|
||||
func TestRunSwapDaemon_NoRelayersAvailable_Refund(t *testing.T) {
|
||||
minXMR := coins.StrToDecimal("1")
|
||||
maxXMR := minXMR
|
||||
|
||||
@@ -57,8 +57,8 @@ func TestDatabase_OfferTable(t *testing.T) {
|
||||
MoneroStartHeight: 12345,
|
||||
StartTime: time.Now().Add(-30 * time.Minute),
|
||||
EndTime: nil,
|
||||
Timeout0: nil,
|
||||
Timeout1: nil,
|
||||
Timeout2: nil,
|
||||
}
|
||||
|
||||
err = db.PutSwap(infoA)
|
||||
@@ -123,8 +123,8 @@ func TestDatabase_GetAllOffers_InvalidEntry(t *testing.T) {
|
||||
Status: types.ExpectingKeys,
|
||||
LastStatusUpdateTime: time.Now(),
|
||||
MoneroStartHeight: 12345,
|
||||
Timeout0: nil,
|
||||
Timeout1: nil,
|
||||
Timeout2: nil,
|
||||
StartTime: time.Now().Add(-30 * time.Minute),
|
||||
EndTime: nil,
|
||||
}
|
||||
@@ -182,8 +182,8 @@ func TestDatabase_SwapTable(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
startTime := time.Now().Add(-2 * time.Minute)
|
||||
timeout0 := time.Now().Add(30 * time.Minute)
|
||||
timeout1 := time.Now().Add(60 * time.Minute)
|
||||
timeout1 := time.Now().Add(30 * time.Minute)
|
||||
timeout2 := time.Now().Add(60 * time.Minute)
|
||||
|
||||
infoA := &swap.Info{
|
||||
Version: swap.CurInfoVersion,
|
||||
@@ -199,8 +199,8 @@ func TestDatabase_SwapTable(t *testing.T) {
|
||||
MoneroStartHeight: 12345,
|
||||
StartTime: startTime,
|
||||
EndTime: nil,
|
||||
Timeout0: &timeout0,
|
||||
Timeout1: &timeout1,
|
||||
Timeout2: &timeout2,
|
||||
}
|
||||
err = db.PutSwap(infoA)
|
||||
require.NoError(t, err)
|
||||
@@ -219,8 +219,8 @@ func TestDatabase_SwapTable(t *testing.T) {
|
||||
MoneroStartHeight: 12345,
|
||||
StartTime: startTime,
|
||||
EndTime: nil,
|
||||
Timeout0: &timeout0,
|
||||
Timeout1: &timeout1,
|
||||
Timeout2: &timeout2,
|
||||
}
|
||||
err = db.PutSwap(infoB)
|
||||
require.NoError(t, err)
|
||||
@@ -242,8 +242,8 @@ func TestDatabase_GetAllSwaps_InvalidEntry(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
startTime := time.Now().Add(-2 * time.Minute)
|
||||
timeout0 := time.Now().Add(30 * time.Minute)
|
||||
timeout1 := time.Now().Add(60 * time.Minute)
|
||||
timeout1 := time.Now().Add(30 * time.Minute)
|
||||
timeout2 := time.Now().Add(60 * time.Minute)
|
||||
|
||||
goodInfo := &swap.Info{
|
||||
Version: swap.CurInfoVersion,
|
||||
@@ -259,8 +259,8 @@ func TestDatabase_GetAllSwaps_InvalidEntry(t *testing.T) {
|
||||
MoneroStartHeight: 12345,
|
||||
StartTime: startTime,
|
||||
EndTime: nil,
|
||||
Timeout0: &timeout0,
|
||||
Timeout1: &timeout1,
|
||||
Timeout2: &timeout2,
|
||||
}
|
||||
err = db.PutSwap(goodInfo)
|
||||
require.NoError(t, err)
|
||||
@@ -306,8 +306,8 @@ func TestDatabase_SwapTable_Update(t *testing.T) {
|
||||
|
||||
id := types.Hash{0x1}
|
||||
startTime := time.Now().Add(-2 * time.Minute)
|
||||
timeout0 := time.Now().Add(30 * time.Minute)
|
||||
timeout1 := time.Now().Add(60 * time.Minute)
|
||||
timeout1 := time.Now().Add(30 * time.Minute)
|
||||
timeout2 := time.Now().Add(60 * time.Minute)
|
||||
|
||||
infoA := &swap.Info{
|
||||
Version: swap.CurInfoVersion,
|
||||
@@ -323,8 +323,8 @@ func TestDatabase_SwapTable_Update(t *testing.T) {
|
||||
MoneroStartHeight: 12345,
|
||||
StartTime: startTime,
|
||||
EndTime: nil,
|
||||
Timeout0: &timeout0,
|
||||
Timeout1: &timeout1,
|
||||
Timeout2: &timeout2,
|
||||
}
|
||||
err = db.PutSwap(infoA)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -42,8 +42,8 @@ func TestRecoveryDB_ContractSwapInfo(t *testing.T) {
|
||||
Claimer: ethcommon.HexToAddress("0xbe0eb53f46cd790cd13851d5eff43d12404d33e8"),
|
||||
PubKeyClaim: ethcommon.HexToHash("0x5ab9467e70d4e98567991f0179d1f82a3096ed7973f7aff9ea50f649cafa88b9"),
|
||||
PubKeyRefund: ethcommon.HexToHash("0x4897bc3b9e02c2a8cd6353b9b29377157bf2694daaf52b59c0b42daa39877f14"),
|
||||
Timeout0: big.NewInt(1672531200),
|
||||
Timeout1: big.NewInt(1672545600),
|
||||
Timeout1: big.NewInt(1672531200),
|
||||
Timeout2: big.NewInt(1672545600),
|
||||
Asset: types.EthAssetETH.Address(),
|
||||
Value: big.NewInt(9876),
|
||||
Nonce: big.NewInt(1234),
|
||||
@@ -59,8 +59,8 @@ func TestRecoveryDB_ContractSwapInfo(t *testing.T) {
|
||||
"claimer": "0xbe0eb53f46cd790cd13851d5eff43d12404d33e8",
|
||||
"pubKeyClaim": "0x5ab9467e70d4e98567991f0179d1f82a3096ed7973f7aff9ea50f649cafa88b9",
|
||||
"pubKeyRefund": "0x4897bc3b9e02c2a8cd6353b9b29377157bf2694daaf52b59c0b42daa39877f14",
|
||||
"timeout0": 1672531200,
|
||||
"timeout1": 1672545600,
|
||||
"timeout1": 1672531200,
|
||||
"timeout2": 1672545600,
|
||||
"asset": "0x0000000000000000000000000000000000000000",
|
||||
"value": 9876,
|
||||
"nonce": 1234
|
||||
@@ -156,8 +156,8 @@ func TestRecoveryDB_DeleteSwap(t *testing.T) {
|
||||
Claimer: ethcommon.HexToAddress("0xbe0eb53f46cd790cd13851d5eff43d12404d33e8"),
|
||||
PubKeyClaim: ethcommon.HexToHash("0x5ab9467e70d4e98567991f0179d1f82a3096ed7973f7aff9ea50f649cafa88b9"),
|
||||
PubKeyRefund: ethcommon.HexToHash("0x4897bc3b9e02c2a8cd6353b9b29377157bf2694daaf52b59c0b42daa39877f14"),
|
||||
Timeout0: big.NewInt(1672531200),
|
||||
Timeout1: big.NewInt(1672545600),
|
||||
Timeout1: big.NewInt(1672531200),
|
||||
Timeout2: big.NewInt(1672545600),
|
||||
Asset: types.EthAssetETH.Address(),
|
||||
Value: big.NewInt(9876),
|
||||
Nonce: big.NewInt(1234),
|
||||
|
||||
20
docs/rpc.md
20
docs/rpc.md
@@ -328,7 +328,7 @@ curl -s -X POST http://127.0.0.1:5000 -H 'Content-Type: application/json' -d \
|
||||
|
||||
### `personal_setSwapTimeout`
|
||||
|
||||
Sets the duration between swap initiation and t0 and t0 and t1, in seconds.
|
||||
Sets the duration between swap initiation and t1 and t1 and t2, in seconds.
|
||||
|
||||
Parameters:
|
||||
- `duration`: duration of timeout, in seconds
|
||||
@@ -344,7 +344,7 @@ curl -X POST http://127.0.0.1:5002 -d '{"jsonrpc":"2.0","id":"0","method":"perso
|
||||
|
||||
### `personal_getSwapTimeout`
|
||||
|
||||
Returns the duration between swap initiation and t0 and t0 and t1, in seconds
|
||||
Returns the duration between swap initiation and t1 and t1 and t2, in seconds
|
||||
|
||||
Parameters:
|
||||
- none
|
||||
@@ -398,8 +398,8 @@ Each items in `swaps` contains:
|
||||
- `exchangeRate`: the exchange rate of the swap, expressed in a ratio of XMR/ETH.
|
||||
- `status`: the swap's status.
|
||||
- `startTime`: the start time of the swap (in RFC 3339 format).
|
||||
- `timeout0`: the time at which the ETH-taker can always claim ETH, and the ETH-maker can no longer refund.
|
||||
- `timeout1`: the time at which the ETH-taker can no longer claim ETH, and the ETH-maker is able to refund.
|
||||
- `timeout1`: the time at which the ETH-taker can always claim ETH, and the ETH-maker can no longer refund.
|
||||
- `timeout2`: the time at which the ETH-taker can no longer claim ETH, and the ETH-maker is able to refund.
|
||||
|
||||
Example:
|
||||
```bash
|
||||
@@ -420,8 +420,8 @@ curl -s -X POST http://127.0.0.1:5000 -H 'Content-Type: application/json' -d \
|
||||
"exchangeRate": "0.05",
|
||||
"status": "ETHLocked",
|
||||
"startTime": "2023-03-18T16:47:50.598029743-04:00",
|
||||
"timeout0": "2023-03-18T16:49:55-04:00",
|
||||
"timeout1": "2023-03-18T16:51:55-04:00"
|
||||
"timeout1": "2023-03-18T16:49:55-04:00",
|
||||
"timeout2": "2023-03-18T16:51:55-04:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -447,8 +447,8 @@ curl -s -X POST http://127.0.0.1:5000 -H 'Content-Type: application/json' -d \
|
||||
"exchangeRate": "1",
|
||||
"status": "ETHLocked",
|
||||
"startTime": "2023-03-18T16:52:56.304958446-04:00",
|
||||
"timeout0": "2023-03-18T16:55:01-04:00",
|
||||
"timeout1": "2023-03-18T16:57:01-04:00"
|
||||
"timeout1": "2023-03-18T16:55:01-04:00",
|
||||
"timeout2": "2023-03-18T16:57:01-04:00"
|
||||
},
|
||||
{
|
||||
"id": "0x8f23b7e187b1db26fcfd23c1699c3e56221153fd7225ada0b0cae8fdbd1cab65",
|
||||
@@ -458,8 +458,8 @@ curl -s -X POST http://127.0.0.1:5000 -H 'Content-Type: application/json' -d \
|
||||
"exchangeRate": "1",
|
||||
"status": "ETHLocked",
|
||||
"startTime": "2023-03-18T16:53:02.642556563-04:00",
|
||||
"timeout0": "2023-03-18T16:55:07-04:00",
|
||||
"timeout1": "2023-03-18T16:57:07-04:00"
|
||||
"timeout1": "2023-03-18T16:55:07-04:00",
|
||||
"timeout2": "2023-03-18T16:57:07-04:00"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -59,7 +59,6 @@ func TestCheckSwapCreatorContractCode_fail(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSepoliaContract(t *testing.T) {
|
||||
t.Skip("needs to be redeployed before merge")
|
||||
ctx := context.Background()
|
||||
ec := tests.NewEthSepoliaClient(t)
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@ contract SwapCreator is Secp256k1 {
|
||||
// this public key is a point on the secp256k1 curve
|
||||
bytes32 pubKeyRefund;
|
||||
// timestamp before which Alice can call either `setReady` or `refund`
|
||||
uint256 timeout0;
|
||||
// timestamp after which Bob cannot claim, only Alice can refund
|
||||
uint256 timeout1;
|
||||
// timestamp after which Bob cannot claim, only Alice can refund
|
||||
uint256 timeout2;
|
||||
// the asset being swapped: equal to address(0) for ETH, or an ERC-20 token address
|
||||
address asset;
|
||||
// the value of this swap
|
||||
@@ -60,8 +60,8 @@ contract SwapCreator is Secp256k1 {
|
||||
bytes32 swapID,
|
||||
bytes32 claimKey,
|
||||
bytes32 refundKey,
|
||||
uint256 timeout0,
|
||||
uint256 timeout1,
|
||||
uint256 timeout2,
|
||||
address asset,
|
||||
uint256 value
|
||||
);
|
||||
@@ -78,7 +78,7 @@ contract SwapCreator is Secp256k1 {
|
||||
// returned when the claimer parameter for `newSwap` is the zero address
|
||||
error InvalidClaimer();
|
||||
|
||||
// returned when the timeout0 or timeout1 parameters for `newSwap` are zero
|
||||
// returned when the timeout1 or timeout2 parameters for `newSwap` are zero
|
||||
error InvalidTimeout();
|
||||
|
||||
// returned when the ether sent with a `newSwap` transaction does not match the value parameter
|
||||
@@ -126,14 +126,14 @@ contract SwapCreator is Secp256k1 {
|
||||
|
||||
// newSwap creates a new Swap instance with the given parameters.
|
||||
// it returns the swap's ID.
|
||||
// _timeoutDuration0: duration between the current timestamp and timeout0
|
||||
// _timeoutDuration1: duration between timeout0 and timeout1
|
||||
// _timeoutDuration0: duration between the current timestamp and timeout1
|
||||
// _timeoutDuration1: duration between timeout1 and timeout2
|
||||
function newSwap(
|
||||
bytes32 _pubKeyClaim,
|
||||
bytes32 _pubKeyRefund,
|
||||
address payable _claimer,
|
||||
uint256 _timeoutDuration0,
|
||||
uint256 _timeoutDuration1,
|
||||
uint256 _timeoutDuration2,
|
||||
address _asset,
|
||||
uint256 _value,
|
||||
uint256 _nonce
|
||||
@@ -149,15 +149,15 @@ contract SwapCreator is Secp256k1 {
|
||||
|
||||
if (_pubKeyClaim == 0 || _pubKeyRefund == 0) revert InvalidSwapKey();
|
||||
if (_claimer == address(0)) revert InvalidClaimer();
|
||||
if (_timeoutDuration0 == 0 || _timeoutDuration1 == 0) revert InvalidTimeout();
|
||||
if (_timeoutDuration1 == 0 || _timeoutDuration2 == 0) revert InvalidTimeout();
|
||||
|
||||
Swap memory swap = Swap({
|
||||
owner: payable(msg.sender),
|
||||
pubKeyClaim: _pubKeyClaim,
|
||||
pubKeyRefund: _pubKeyRefund,
|
||||
claimer: _claimer,
|
||||
timeout0: block.timestamp + _timeoutDuration0,
|
||||
timeout1: block.timestamp + _timeoutDuration0 + _timeoutDuration1,
|
||||
timeout1: block.timestamp + _timeoutDuration1,
|
||||
timeout2: block.timestamp + _timeoutDuration1 + _timeoutDuration2,
|
||||
asset: _asset,
|
||||
value: _value,
|
||||
nonce: _nonce
|
||||
@@ -172,8 +172,8 @@ contract SwapCreator is Secp256k1 {
|
||||
swapID,
|
||||
_pubKeyClaim,
|
||||
_pubKeyRefund,
|
||||
swap.timeout0,
|
||||
swap.timeout1,
|
||||
swap.timeout2,
|
||||
swap.asset,
|
||||
swap.value
|
||||
);
|
||||
@@ -181,7 +181,7 @@ contract SwapCreator is Secp256k1 {
|
||||
return swapID;
|
||||
}
|
||||
|
||||
// Alice should call setReady() before timeout0 once she verifies the XMR has been locked
|
||||
// Alice should call setReady() before timeout1 once she verifies the XMR has been locked
|
||||
function setReady(Swap memory _swap) public {
|
||||
bytes32 swapID = keccak256(abi.encode(_swap));
|
||||
if (swaps[swapID] != Stage.PENDING) revert SwapNotPending();
|
||||
@@ -190,8 +190,9 @@ contract SwapCreator is Secp256k1 {
|
||||
emit Ready(swapID);
|
||||
}
|
||||
|
||||
// Bob can claim if:
|
||||
// - (Alice has set the swap to `ready` or it's past timeout0) and it's before timeout1
|
||||
// Bob can call claim if either of these hold true:
|
||||
// (1) Alice has set the swap to `ready` and it's before timeout1
|
||||
// (2) It is between timeout0 and timeout1
|
||||
function claim(Swap memory _swap, bytes32 _secret) public {
|
||||
if (msg.sender != _swap.claimer) revert OnlySwapClaimer();
|
||||
_claim(_swap, _secret);
|
||||
@@ -207,11 +208,14 @@ contract SwapCreator is Secp256k1 {
|
||||
}
|
||||
}
|
||||
|
||||
// Bob can claim if:
|
||||
// - (Alice has set the swap to `ready` or it's past timeout0) and it's before timeout1
|
||||
// It transfers the fee to the relayer address specified in `_relaySwap`.
|
||||
// Note: this function will revert if the swap value is less than the relayer fee;
|
||||
// in that case, `claim` must be called instead.
|
||||
// Anyone can call claimRelayer if they receive a signed _relaySwap object
|
||||
// from Bob. The same rules for when Bob can call claim() apply here when a
|
||||
// 3rd party relays a claim for Bob. This version of claiming transfers a
|
||||
// _relaySwap.fee to _relayer. To prevent front-running, while not requiring
|
||||
// Bob to know the relayer's payout address, Bob only signs a salted hash of
|
||||
// the relayer's payout address in _relaySwap.relayerHash.
|
||||
// Note: claimRelayer will revert if the swap value is less than the relayer
|
||||
// fee; in that case, Bob must call claim directly.
|
||||
function claimRelayer(
|
||||
RelaySwap memory _relaySwap,
|
||||
bytes32 _secret,
|
||||
@@ -250,8 +254,8 @@ contract SwapCreator is Secp256k1 {
|
||||
Stage swapStage = swaps[swapID];
|
||||
if (swapStage == Stage.INVALID) revert InvalidSwap();
|
||||
if (swapStage == Stage.COMPLETED) revert SwapCompleted();
|
||||
if (block.timestamp < _swap.timeout0 && swapStage != Stage.READY) revert TooEarlyToClaim();
|
||||
if (block.timestamp >= _swap.timeout1) revert TooLateToClaim();
|
||||
if (block.timestamp < _swap.timeout1 && swapStage != Stage.READY) revert TooEarlyToClaim();
|
||||
if (block.timestamp >= _swap.timeout2) revert TooLateToClaim();
|
||||
|
||||
verifySecret(_secret, _swap.pubKeyClaim);
|
||||
emit Claimed(swapID, _secret);
|
||||
@@ -259,8 +263,8 @@ contract SwapCreator is Secp256k1 {
|
||||
}
|
||||
|
||||
// Alice can claim a refund:
|
||||
// - Until timeout0 unless she calls setReady
|
||||
// - After timeout1
|
||||
// - Until timeout1 unless she calls setReady
|
||||
// - After timeout2
|
||||
function refund(Swap memory _swap, bytes32 _secret) public {
|
||||
bytes32 swapID = keccak256(abi.encode(_swap));
|
||||
Stage swapStage = swaps[swapID];
|
||||
@@ -268,8 +272,8 @@ contract SwapCreator is Secp256k1 {
|
||||
if (swapStage == Stage.COMPLETED) revert SwapCompleted();
|
||||
if (_swap.owner != msg.sender) revert OnlySwapOwner();
|
||||
if (
|
||||
block.timestamp < _swap.timeout1 &&
|
||||
(block.timestamp > _swap.timeout0 || swapStage == Stage.READY)
|
||||
block.timestamp < _swap.timeout2 &&
|
||||
(block.timestamp > _swap.timeout1 || swapStage == Stage.READY)
|
||||
) revert NotTimeToRefund();
|
||||
|
||||
verifySecret(_secret, _swap.pubKeyRefund);
|
||||
|
||||
@@ -81,7 +81,7 @@ func TestSwapCreator_Claim_ERC20(t *testing.T) {
|
||||
testClaim(t, types.EthAsset(tokenAddr), 2, big.NewInt(99), tokenContract)
|
||||
}
|
||||
|
||||
func TestSwapCreator_RefundBeforeT0_ERC20(t *testing.T) {
|
||||
func TestSwapCreator_RefundBeforeT1_ERC20(t *testing.T) {
|
||||
pkA := tests.GetTakerTestKey(t)
|
||||
ec, _ := tests.NewEthClient(t)
|
||||
|
||||
@@ -95,10 +95,10 @@ func TestSwapCreator_RefundBeforeT0_ERC20(t *testing.T) {
|
||||
9999,
|
||||
)
|
||||
|
||||
testRefundBeforeT0(t, types.EthAsset(tokenAddr), tokenContract, 2)
|
||||
testRefundBeforeT1(t, types.EthAsset(tokenAddr), tokenContract, 2)
|
||||
}
|
||||
|
||||
func TestSwapCreator_RefundAfterT1_ERC20(t *testing.T) {
|
||||
func TestSwapCreator_RefundAfterT2_ERC20(t *testing.T) {
|
||||
pkA := tests.GetTakerTestKey(t)
|
||||
ec, _ := tests.NewEthClient(t)
|
||||
|
||||
@@ -112,5 +112,5 @@ func TestSwapCreator_RefundAfterT1_ERC20(t *testing.T) {
|
||||
9999,
|
||||
)
|
||||
|
||||
testRefundAfterT1(t, types.EthAsset(tokenAddr), tokenContract, 2)
|
||||
testRefundAfterT2(t, types.EthAsset(tokenAddr), tokenContract, 2)
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -19,8 +19,8 @@ type swap struct {
|
||||
Claimer common.Address `json:"claimer" validate:"required"`
|
||||
PubKeyClaim types.Hash `json:"pubKeyClaim" validate:"required"`
|
||||
PubKeyRefund types.Hash `json:"pubKeyRefund" validate:"required"`
|
||||
Timeout0 *big.Int `json:"timeout0" validate:"required"`
|
||||
Timeout1 *big.Int `json:"timeout1" validate:"required"`
|
||||
Timeout2 *big.Int `json:"timeout2" validate:"required"`
|
||||
Asset common.Address `json:"asset"`
|
||||
Value *big.Int `json:"value" validate:"required"`
|
||||
Nonce *big.Int `json:"nonce" validate:"required"`
|
||||
@@ -33,8 +33,8 @@ func (sfs *SwapCreatorSwap) MarshalJSON() ([]byte, error) {
|
||||
Claimer: sfs.Claimer,
|
||||
PubKeyClaim: sfs.PubKeyClaim,
|
||||
PubKeyRefund: sfs.PubKeyRefund,
|
||||
Timeout0: sfs.Timeout0,
|
||||
Timeout1: sfs.Timeout1,
|
||||
Timeout2: sfs.Timeout2,
|
||||
Asset: sfs.Asset,
|
||||
Value: sfs.Value,
|
||||
Nonce: sfs.Nonce,
|
||||
@@ -52,8 +52,8 @@ func (sfs *SwapCreatorSwap) UnmarshalJSON(data []byte) error {
|
||||
Claimer: s.Claimer,
|
||||
PubKeyClaim: s.PubKeyClaim,
|
||||
PubKeyRefund: s.PubKeyRefund,
|
||||
Timeout0: s.Timeout0,
|
||||
Timeout1: s.Timeout1,
|
||||
Timeout2: s.Timeout2,
|
||||
Asset: s.Asset,
|
||||
Value: s.Value,
|
||||
Nonce: s.Nonce,
|
||||
|
||||
@@ -23,8 +23,8 @@ func TestSwapCreatorSwap_JSON(t *testing.T) {
|
||||
Claimer: ethcommon.HexToAddress("0xbe0eb53f46cd790cd13851d5eff43d12404d33e8"),
|
||||
PubKeyClaim: ethcommon.HexToHash("0x5ab9467e70d4e98567991f0179d1f82a3096ed7973f7aff9ea50f649cafa88b9"),
|
||||
PubKeyRefund: ethcommon.HexToHash("0x4897bc3b9e02c2a8cd6353b9b29377157bf2694daaf52b59c0b42daa39877f14"),
|
||||
Timeout0: big.NewInt(1672531200),
|
||||
Timeout1: big.NewInt(1672545600),
|
||||
Timeout1: big.NewInt(1672531200),
|
||||
Timeout2: big.NewInt(1672545600),
|
||||
Asset: ethcommon.HexToAddress("0xdac17f958d2ee523a2206206994597c13d831ec7"),
|
||||
Value: coins.EtherToWei(apd.New(9876, 0)).BigInt(),
|
||||
Nonce: big.NewInt(1234),
|
||||
@@ -34,8 +34,8 @@ func TestSwapCreatorSwap_JSON(t *testing.T) {
|
||||
"claimer": "0xbe0eb53f46cd790cd13851d5eff43d12404d33e8",
|
||||
"pubKeyClaim": "0x5ab9467e70d4e98567991f0179d1f82a3096ed7973f7aff9ea50f649cafa88b9",
|
||||
"pubKeyRefund": "0x4897bc3b9e02c2a8cd6353b9b29377157bf2694daaf52b59c0b42daa39877f14",
|
||||
"timeout0": 1672531200,
|
||||
"timeout1": 1672545600,
|
||||
"timeout1": 1672531200,
|
||||
"timeout2": 1672545600,
|
||||
"asset": "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||
"value": 9876000000000000000000,
|
||||
"nonce": 1234
|
||||
|
||||
@@ -134,7 +134,7 @@ func testNewSwap(t *testing.T, asset types.EthAsset, erc20Contract *TestERC20) {
|
||||
swapID, err := GetIDFromLog(receipt.Logs[newSwapLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := GetTimeoutsFromLog(receipt.Logs[newSwapLogIndex])
|
||||
t1, t2, err := GetTimeoutsFromLog(receipt.Logs[newSwapLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
// validate that off-chain swapID calculation matches the on-chain value
|
||||
@@ -143,8 +143,8 @@ func testNewSwap(t *testing.T, asset types.EthAsset, erc20Contract *TestERC20) {
|
||||
Claimer: claimer,
|
||||
PubKeyClaim: pubKeyClaim,
|
||||
PubKeyRefund: pubKeyRefund,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: asset.Address(),
|
||||
Value: value,
|
||||
Nonce: nonce,
|
||||
@@ -197,7 +197,7 @@ func TestSwapCreator_Claim_vec(t *testing.T) {
|
||||
id, err := GetIDFromLog(receipt.Logs[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := GetTimeoutsFromLog(receipt.Logs[0])
|
||||
t1, t2, err := GetTimeoutsFromLog(receipt.Logs[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
swap := SwapCreatorSwap{
|
||||
@@ -205,8 +205,8 @@ func TestSwapCreator_Claim_vec(t *testing.T) {
|
||||
Claimer: addr,
|
||||
PubKeyClaim: cmt,
|
||||
PubKeyRefund: dummySwapKey,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: ethcommon.Address(types.EthAssetETH),
|
||||
Value: defaultSwapValue,
|
||||
Nonce: nonce,
|
||||
@@ -280,7 +280,7 @@ func testClaim(t *testing.T, asset types.EthAsset, newLogIndex int, value *big.I
|
||||
id, err := GetIDFromLog(receipt.Logs[newLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := GetTimeoutsFromLog(receipt.Logs[newLogIndex])
|
||||
t1, t2, err := GetTimeoutsFromLog(receipt.Logs[newLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
swap := SwapCreatorSwap{
|
||||
@@ -288,8 +288,8 @@ func testClaim(t *testing.T, asset types.EthAsset, newLogIndex int, value *big.I
|
||||
Claimer: addr,
|
||||
PubKeyClaim: cmt,
|
||||
PubKeyRefund: dummySwapKey,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: asset.Address(),
|
||||
Value: value,
|
||||
Nonce: nonce,
|
||||
@@ -328,7 +328,7 @@ func TestSwapCreator_Claim_random(t *testing.T) {
|
||||
testClaim(t, types.EthAssetETH, 0, defaultSwapValue, nil)
|
||||
}
|
||||
|
||||
func testRefundBeforeT0(t *testing.T, asset types.EthAsset, erc20Contract *TestERC20, newLogIndex int) {
|
||||
func testRefundBeforeT1(t *testing.T, asset types.EthAsset, erc20Contract *TestERC20, newLogIndex int) {
|
||||
// generate refund secret and public key
|
||||
dleq := &dleq.DefaultDLEq{}
|
||||
proof, err := dleq.Prove()
|
||||
@@ -373,7 +373,7 @@ func testRefundBeforeT0(t *testing.T, asset types.EthAsset, erc20Contract *TestE
|
||||
id, err := GetIDFromLog(receipt.Logs[newLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := GetTimeoutsFromLog(receipt.Logs[newLogIndex])
|
||||
t1, t2, err := GetTimeoutsFromLog(receipt.Logs[newLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
swap := SwapCreatorSwap{
|
||||
@@ -381,8 +381,8 @@ func testRefundBeforeT0(t *testing.T, asset types.EthAsset, erc20Contract *TestE
|
||||
Claimer: addr,
|
||||
PubKeyClaim: dummySwapKey,
|
||||
PubKeyRefund: cmt,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: asset.Address(),
|
||||
Value: defaultSwapValue,
|
||||
Nonce: nonce,
|
||||
@@ -408,11 +408,11 @@ func testRefundBeforeT0(t *testing.T, asset types.EthAsset, erc20Contract *TestE
|
||||
require.Equal(t, StageCompleted, stage)
|
||||
}
|
||||
|
||||
func TestSwapCreator_Refund_beforeT0(t *testing.T) {
|
||||
testRefundBeforeT0(t, types.EthAssetETH, nil, 0)
|
||||
func TestSwapCreator_Refund_beforeT1(t *testing.T) {
|
||||
testRefundBeforeT1(t, types.EthAssetETH, nil, 0)
|
||||
}
|
||||
|
||||
func testRefundAfterT1(t *testing.T, asset types.EthAsset, erc20Contract *TestERC20, newLogIndex int) {
|
||||
func testRefundAfterT2(t *testing.T, asset types.EthAsset, erc20Contract *TestERC20, newLogIndex int) {
|
||||
ctx := context.Background()
|
||||
|
||||
// generate refund secret and public key
|
||||
@@ -460,18 +460,18 @@ func testRefundAfterT1(t *testing.T, asset types.EthAsset, erc20Contract *TestER
|
||||
id, err := GetIDFromLog(receipt.Logs[newLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := GetTimeoutsFromLog(receipt.Logs[newLogIndex])
|
||||
t1, t2, err := GetTimeoutsFromLog(receipt.Logs[newLogIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
// ensure we can't refund between T0 and T1
|
||||
<-time.After(time.Until(time.Unix(t0.Int64()+1, 0)))
|
||||
// ensure we can't refund between T1 and T2
|
||||
<-time.After(time.Until(time.Unix(t1.Int64()+1, 0)))
|
||||
swap := SwapCreatorSwap{
|
||||
Owner: addr,
|
||||
Claimer: addr,
|
||||
PubKeyClaim: dummySwapKey,
|
||||
PubKeyRefund: cmt,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: asset.Address(),
|
||||
Value: defaultSwapValue,
|
||||
Nonce: nonce,
|
||||
@@ -483,7 +483,7 @@ func testRefundAfterT1(t *testing.T, asset types.EthAsset, erc20Contract *TestER
|
||||
_, err = block.WaitForReceipt(ctx, ec, tx.Hash())
|
||||
require.ErrorContains(t, err, "VM Exception while processing transaction: revert")
|
||||
|
||||
<-time.After(time.Until(time.Unix(t1.Int64()+1, 0)))
|
||||
<-time.After(time.Until(time.Unix(t2.Int64()+1, 0)))
|
||||
|
||||
// now let's try to refund
|
||||
tx, err = swapCreator.Refund(getAuth(t, pkA), swap, secret)
|
||||
@@ -506,8 +506,8 @@ func testRefundAfterT1(t *testing.T, asset types.EthAsset, erc20Contract *TestER
|
||||
require.Equal(t, StageCompleted, stage)
|
||||
}
|
||||
|
||||
func TestSwapCreator_Refund_afterT1(t *testing.T) {
|
||||
testRefundAfterT1(t, types.EthAssetETH, nil, 0)
|
||||
func TestSwapCreator_Refund_afterT2(t *testing.T) {
|
||||
testRefundAfterT2(t, types.EthAssetETH, nil, 0)
|
||||
}
|
||||
|
||||
// test case where contract has multiple swaps happening at once
|
||||
@@ -549,8 +549,8 @@ func TestSwapCreator_MultipleSwaps(t *testing.T) {
|
||||
Claimer: addrSwap,
|
||||
PubKeyClaim: res.Secp256k1PublicKey().Keccak256(),
|
||||
PubKeyRefund: dummySwapKey, // no one calls refund in this test
|
||||
Timeout0: nil, // timeouts initialised when swap is created
|
||||
Timeout1: nil,
|
||||
Timeout1: nil, // timeouts initialised when swap is created
|
||||
Timeout2: nil,
|
||||
Asset: ethcommon.Address(types.EthAssetETH),
|
||||
Value: defaultSwapValue,
|
||||
Nonce: big.NewInt(int64(i)),
|
||||
@@ -591,7 +591,7 @@ func TestSwapCreator_MultipleSwaps(t *testing.T) {
|
||||
sc.id, err = GetIDFromLog(receipt.Logs[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
sc.swap.Timeout0, sc.swap.Timeout1, err = GetTimeoutsFromLog(receipt.Logs[0])
|
||||
sc.swap.Timeout1, sc.swap.Timeout2, err = GetTimeoutsFromLog(receipt.Logs[0])
|
||||
require.NoError(t, err)
|
||||
}(&swapCases[i])
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ func (s *SwapCreatorRelaySwap) Hash() types.Hash {
|
||||
s.Swap.Claimer,
|
||||
s.Swap.PubKeyClaim,
|
||||
s.Swap.PubKeyRefund,
|
||||
s.Swap.Timeout0,
|
||||
s.Swap.Timeout1,
|
||||
s.Swap.Timeout2,
|
||||
s.Swap.Asset,
|
||||
s.Swap.Value,
|
||||
s.Swap.Nonce,
|
||||
@@ -189,8 +189,8 @@ func (sfs *SwapCreatorSwap) SwapID() types.Hash {
|
||||
sfs.Claimer,
|
||||
sfs.PubKeyClaim,
|
||||
sfs.PubKeyRefund,
|
||||
sfs.Timeout0,
|
||||
sfs.Timeout1,
|
||||
sfs.Timeout2,
|
||||
sfs.Asset,
|
||||
sfs.Value,
|
||||
sfs.Nonce,
|
||||
@@ -290,9 +290,9 @@ func GetTimeoutsFromLog(log *ethtypes.Log) (*big.Int, *big.Int, error) {
|
||||
return nil, nil, errors.New("log didn't have enough parameters")
|
||||
}
|
||||
|
||||
t0 := res[3].(*big.Int)
|
||||
t1 := res[4].(*big.Int)
|
||||
return t0, t1, nil
|
||||
t1 := res[3].(*big.Int)
|
||||
t2 := res[4].(*big.Int)
|
||||
return t1, t2, nil
|
||||
}
|
||||
|
||||
// GenerateNewSwapNonce generates a random nonce value for use with NewSwap
|
||||
|
||||
@@ -186,7 +186,7 @@ func (h *Host) SubmitRelayRequest(relayerID peer.ID, request *RelayClaimRequest)
|
||||
|
||||
func receiveRelayClaimResponse(stream libp2pnetwork.Stream) (*RelayClaimResponse, error) {
|
||||
// The timeout should be short enough, that the Maker can try multiple relayers
|
||||
// before T1 expires even if the receiving node accepts the relay request and
|
||||
// before T2 expires even if the receiving node accepts the relay request and
|
||||
// just sits on it without doing anything.
|
||||
const relayResponseTimeout = time.Minute
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ func createTestClaimRequest() *message.RelayClaimRequest {
|
||||
Claimer: ethcommon.Address{0x1},
|
||||
PubKeyClaim: [32]byte{0x1},
|
||||
PubKeyRefund: [32]byte{0x1},
|
||||
Timeout0: big.NewInt(time.Now().Add(30 * time.Minute).Unix()),
|
||||
Timeout1: big.NewInt(time.Now().Add(60 * time.Minute).Unix()),
|
||||
Timeout1: big.NewInt(time.Now().Add(30 * time.Minute).Unix()),
|
||||
Timeout2: big.NewInt(time.Now().Add(60 * time.Minute).Unix()),
|
||||
Asset: ethcommon.Address(types.EthAssetETH),
|
||||
Value: big.NewInt(1e18),
|
||||
Nonce: big.NewInt(1),
|
||||
|
||||
@@ -208,8 +208,8 @@ func (b *backend) SwapTimeout() time.Duration {
|
||||
return b.swapTimeout
|
||||
}
|
||||
|
||||
// SetSwapTimeout sets the duration between the swap being initiated on-chain and the timeout t0,
|
||||
// and the duration between t0 and t1.
|
||||
// SetSwapTimeout sets the duration between the swap being initiated on-chain and the timeout t1,
|
||||
// and the duration between t1 and t2.
|
||||
func (b *backend) SetSwapTimeout(timeout time.Duration) {
|
||||
b.swapTimeout = timeout
|
||||
}
|
||||
|
||||
@@ -53,17 +53,17 @@ type Info struct {
|
||||
// EndTime is the time at which the swap completes; ie.
|
||||
// when the node has claimed or refunded its funds.
|
||||
EndTime *time.Time `json:"endTime,omitempty"`
|
||||
// Timeout0 is the first swap timeout; before this timeout,
|
||||
// Timeout1 is the first swap timeout; before this timeout,
|
||||
// the ETH-maker is able to refund the ETH (if `ready` has not
|
||||
// been set to true in the contract). After this timeout,
|
||||
// the ETH-taker is able to claim, and the ETH-maker can
|
||||
// no longer refund.
|
||||
Timeout0 *time.Time `json:"timeout0,omitempty"`
|
||||
// Timeout1 is the second swap timeout; before this timeout
|
||||
// (and after Timeout0), the ETH-taker is able to claim, but
|
||||
Timeout1 *time.Time `json:"timeout1,omitempty"`
|
||||
// Timeout2 is the second swap timeout; before this timeout
|
||||
// (and after Timeout1), the ETH-taker is able to claim, but
|
||||
// after this timeout, the ETH-taker can no longer claim, only
|
||||
// the ETH-maker can refund.
|
||||
Timeout1 *time.Time `json:"timeout1,omitempty"`
|
||||
Timeout2 *time.Time `json:"timeout2,omitempty"`
|
||||
statusCh chan types.Status `json:"-"`
|
||||
}
|
||||
|
||||
|
||||
@@ -102,13 +102,14 @@ func (s *swapState) checkContract(txHash ethcommon.Hash) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// checkAndSetTimeouts checks that the timeouts set by the counterparty when initiating the swap
|
||||
// are not too short or too long.
|
||||
// we expect the timeout to be of a certain length (1 hour for mainnet/stagenet), and allow a 3 minute
|
||||
// variation between now and the expected time until the first timeout t0, to allow for block confirmations.
|
||||
// the time between t0 and t1 should always be the exact length we expect.
|
||||
func (s *swapState) checkAndSetTimeouts(t0, t1 *big.Int) error {
|
||||
s.setTimeouts(t0, t1)
|
||||
// checkAndSetTimeouts checks that the timeouts set by the counterparty when
|
||||
// initiating a swap are not too short or long. We expect the timeout to be of a
|
||||
// certain length (1 hour for mainnet/stagenet), and allow a 3 minute variation
|
||||
// between now and the expected time until the first timeout t1, to allow for
|
||||
// block confirmations. The time between t1 and t2 should always be the exact
|
||||
// length we expect.
|
||||
func (s *swapState) checkAndSetTimeouts(t1, t2 *big.Int) error {
|
||||
s.setTimeouts(t1, t2)
|
||||
|
||||
// we ignore the timeout for development, as unit tests and integration tests
|
||||
// often set different timeouts.
|
||||
@@ -119,20 +120,20 @@ func (s *swapState) checkAndSetTimeouts(t0, t1 *big.Int) error {
|
||||
expectedTimeout := common.SwapTimeoutFromEnv(s.Backend.Env())
|
||||
allowableTimeDiff := expectedTimeout / 20
|
||||
|
||||
if s.t1.Sub(s.t0) != expectedTimeout {
|
||||
return errInvalidT1
|
||||
if s.t2.Sub(s.t1) != expectedTimeout {
|
||||
return errInvalidT2
|
||||
}
|
||||
|
||||
if time.Now().Add(expectedTimeout).Sub(s.t0).Abs() > allowableTimeDiff {
|
||||
return errInvalidT0
|
||||
if time.Now().Add(expectedTimeout).Sub(s.t1).Abs() > allowableTimeDiff {
|
||||
return errInvalidT1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *swapState) setTimeouts(t0, t1 *big.Int) {
|
||||
s.t0 = time.Unix(t0.Int64(), 0)
|
||||
func (s *swapState) setTimeouts(t1, t2 *big.Int) {
|
||||
s.t1 = time.Unix(t1.Int64(), 0)
|
||||
s.info.Timeout0 = &s.t0
|
||||
s.t2 = time.Unix(t2.Int64(), 0)
|
||||
s.info.Timeout1 = &s.t1
|
||||
s.info.Timeout2 = &s.t2
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ var (
|
||||
errSwapIDMismatch = errors.New("hash of swap struct does not match swap ID")
|
||||
errLockTxReverted = errors.New("other party failed to lock ETH asset (transaction reverted)")
|
||||
errInvalidETHLockedTransaction = errors.New("eth locked tx was not to correct contract address")
|
||||
errInvalidT0 = errors.New("invalid t0 value; asset was locked too far in the past")
|
||||
errInvalidT1 = errors.New("invalid swap timeout set by counterparty")
|
||||
errInvalidT1 = errors.New("invalid t1 value; asset was locked too far in the past")
|
||||
errInvalidT2 = errors.New("invalid swap timeout set by counterparty")
|
||||
errRelayedTransactionTimeout = errors.New("relayed transaction was not included within one minute")
|
||||
errClaimedLogInvalidContractAddr = errors.New("log was not emitted by correct contract")
|
||||
errClaimedLogWrongTopicLength = errors.New("log did not have 3 topics")
|
||||
|
||||
@@ -24,10 +24,10 @@ const (
|
||||
EventETHLockedType EventType = iota
|
||||
|
||||
// EventContractReadyType is triggered when the taker sets the contract to
|
||||
// "ready" or timeout0 is reached. When this event occurs, we can claim ETH
|
||||
// "ready" or timeout1 is reached. When this event occurs, we can claim ETH
|
||||
// from the contract. After this event, the other possible events are
|
||||
// EventETHRefundedType (which would only happen if we go offline until
|
||||
// timeout1, causing us to refund), or EventExitType (refund).
|
||||
// timeout2, causing us to refund), or EventExitType (refund).
|
||||
EventContractReadyType
|
||||
|
||||
// EventETHRefundedType is triggered when the taker refunds the
|
||||
|
||||
@@ -210,8 +210,8 @@ func TestInstance_createOngoingSwap(t *testing.T) {
|
||||
SwapCreatorAddr: inst.backend.SwapCreatorAddr(),
|
||||
SwapID: contractSwapID,
|
||||
Swap: &contracts.SwapCreatorSwap{
|
||||
Timeout0: big.NewInt(1),
|
||||
Timeout1: big.NewInt(2),
|
||||
Timeout1: big.NewInt(1),
|
||||
Timeout2: big.NewInt(2),
|
||||
},
|
||||
}, nil)
|
||||
rdb.EXPECT().GetSwapPrivateKey(s.OfferID).Return(
|
||||
|
||||
@@ -128,7 +128,7 @@ func (s *swapState) handleNotifyETHLocked(msg *message.NotifyETHLocked) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.checkAndSetTimeouts(msg.ContractSwap.Timeout0, msg.ContractSwap.Timeout1)
|
||||
err = s.checkAndSetTimeouts(msg.ContractSwap.Timeout1, msg.ContractSwap.Timeout2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -138,14 +138,14 @@ func (s *swapState) handleNotifyETHLocked(msg *message.NotifyETHLocked) error {
|
||||
return fmt.Errorf("failed to lock funds: %w", err)
|
||||
}
|
||||
|
||||
go s.runT0ExpirationHandler()
|
||||
go s.runT1ExpirationHandler()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *swapState) runT0ExpirationHandler() {
|
||||
log.Debugf("time until t0 (%s): %vs",
|
||||
s.t0.Format(common.TimeFmtSecs),
|
||||
time.Until(s.t0).Seconds(),
|
||||
func (s *swapState) runT1ExpirationHandler() {
|
||||
log.Debugf("time until t1 (%s): %vs",
|
||||
s.t1.Format(common.TimeFmtSecs),
|
||||
time.Until(s.t1).Seconds(),
|
||||
)
|
||||
|
||||
waitCtx, waitCtxCancel := context.WithCancel(context.Background())
|
||||
@@ -155,7 +155,7 @@ func (s *swapState) runT0ExpirationHandler() {
|
||||
// with --miner.blockTime!!!
|
||||
waitCh := make(chan error)
|
||||
go func() {
|
||||
waitCh <- s.ETHClient().WaitForTimestamp(waitCtx, s.t0)
|
||||
waitCh <- s.ETHClient().WaitForTimestamp(waitCtx, s.t1)
|
||||
close(waitCh)
|
||||
}()
|
||||
|
||||
@@ -163,27 +163,27 @@ func (s *swapState) runT0ExpirationHandler() {
|
||||
case <-s.ctx.Done():
|
||||
return
|
||||
case <-s.readyCh:
|
||||
log.Debugf("returning from runT0ExpirationHandler as contract was set to ready")
|
||||
log.Debugf("returning from runT1ExpirationHandler as contract was set to ready")
|
||||
return
|
||||
case err := <-waitCh:
|
||||
if err != nil {
|
||||
// TODO: Do we propagate this error? If we retry, the logic should probably be inside
|
||||
// WaitForTimestamp. (#162)
|
||||
log.Errorf("Failure waiting for T0 timeout: err=%s", err)
|
||||
log.Errorf("Failure waiting for T1 timeout: err=%s", err)
|
||||
return
|
||||
}
|
||||
log.Debugf("reached t0, time to claim")
|
||||
s.handleT0Expired()
|
||||
log.Debugf("reached t1, time to claim")
|
||||
s.handleT1Expired()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *swapState) handleT0Expired() {
|
||||
func (s *swapState) handleT1Expired() {
|
||||
event := newEventContractReady()
|
||||
s.eventCh <- event
|
||||
err := <-event.errCh
|
||||
if err != nil {
|
||||
// TODO: this is quite bad, how should this be handled? (#162)
|
||||
log.Errorf("failed to handle t0 expiration: %s", err)
|
||||
log.Errorf("failed to handle t1 expiration: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ type swapState struct {
|
||||
swapCreatorAddr ethcommon.Address
|
||||
contractSwapID [32]byte
|
||||
contractSwap *contracts.SwapCreatorSwap
|
||||
t0, t1 time.Time
|
||||
t1, t2 time.Time
|
||||
|
||||
// XMRTaker's keys for this session
|
||||
xmrtakerPublicSpendKey *mcrypto.PublicKey
|
||||
@@ -89,7 +89,7 @@ type swapState struct {
|
||||
logReadyCh chan ethtypes.Log
|
||||
// channel for `Refunded` logs seen on-chain
|
||||
logRefundedCh chan ethtypes.Log
|
||||
// signals the t0 expiration handler to return
|
||||
// signals the t1 expiration handler to return
|
||||
readyCh chan struct{}
|
||||
// signals to the creator xmrmaker instance that it can delete this swap
|
||||
done chan struct{}
|
||||
@@ -312,7 +312,7 @@ func newSwapStateFromOngoing(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.setTimeouts(ethSwapInfo.Swap.Timeout0, ethSwapInfo.Swap.Timeout1)
|
||||
s.setTimeouts(ethSwapInfo.Swap.Timeout1, ethSwapInfo.Swap.Timeout2)
|
||||
s.privkeys = sk
|
||||
s.pubkeys = sk.PublicKeyPair()
|
||||
s.contractSwapID = ethSwapInfo.SwapID
|
||||
|
||||
@@ -97,7 +97,7 @@ func newTestSwap(
|
||||
contractSwapID, err := contracts.GetIDFromLog(receipt.Logs[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := contracts.GetTimeoutsFromLog(receipt.Logs[0])
|
||||
t1, t2, err := contracts.GetTimeoutsFromLog(receipt.Logs[0])
|
||||
require.NoError(t, err)
|
||||
|
||||
contractSwap := &contracts.SwapCreatorSwap{
|
||||
@@ -105,8 +105,8 @@ func newTestSwap(
|
||||
Claimer: ethAddr,
|
||||
PubKeyClaim: claimKey,
|
||||
PubKeyRefund: refundKey,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: ethcommon.Address(asset),
|
||||
Value: amount,
|
||||
Nonce: nonce,
|
||||
@@ -133,7 +133,7 @@ func newSwap(
|
||||
|
||||
ss.contractSwapID = contractSwapID
|
||||
ss.contractSwap = contractSwap
|
||||
ss.setTimeouts(contractSwap.Timeout0, contractSwap.Timeout1)
|
||||
ss.setTimeouts(contractSwap.Timeout1, contractSwap.Timeout2)
|
||||
return txHash
|
||||
}
|
||||
|
||||
@@ -252,10 +252,10 @@ func TestSwapState_HandleProtocolMessage_NotifyETHLocked_timeout(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
err = s.setNextExpectedEvent(EventContractReadyType)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, duration, s.t1.Sub(s.t0))
|
||||
require.Equal(t, duration, s.t2.Sub(s.t1))
|
||||
require.Equal(t, EventContractReadyType, s.nextExpectedEvent)
|
||||
|
||||
go s.runT0ExpirationHandler()
|
||||
go s.runT1ExpirationHandler()
|
||||
|
||||
for status := range s.info.StatusCh() {
|
||||
if status == types.CompletedSuccess {
|
||||
|
||||
@@ -39,8 +39,8 @@ const (
|
||||
EventETHClaimedType
|
||||
|
||||
// EventShouldRefundType is triggered when we should refund, either because
|
||||
// we are nearing the timeout0 threshold and the maker hasn't locked XMR, or
|
||||
// because we've reached the timeout1 threshold and the maker hasn't claimed
|
||||
// we are nearing the timeout1 threshold and the maker hasn't locked XMR, or
|
||||
// because we've reached the timeout2 threshold and the maker hasn't claimed
|
||||
// the ETH. It causes us to refund the contract locked ETH locked to
|
||||
// ourselves. After this event, the only possible event is EventExitType
|
||||
// (refund path).
|
||||
@@ -168,7 +168,7 @@ func newEventETHClaimed(sk *mcrypto.PrivateSpendKey) *EventETHClaimed {
|
||||
}
|
||||
|
||||
// EventShouldRefund is an optional event. It occurs when the XMR-maker doesn't
|
||||
// lock before t0, so we should refund the ETH.
|
||||
// lock before t1, so we should refund the ETH.
|
||||
type EventShouldRefund struct {
|
||||
errCh chan error
|
||||
txHashCh chan ethcommon.Hash // contains the refund tx hash, if successful
|
||||
|
||||
@@ -84,7 +84,7 @@ func TestSwapState_handleEvent_EventETHClaimed(t *testing.T) {
|
||||
resp := net.LastSentMessage()
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, message.NotifyETHLockedType, resp.Type())
|
||||
require.Equal(t, time.Minute*2, s.t1.Sub(s.t0))
|
||||
require.Equal(t, time.Minute*2, s.t2.Sub(s.t1))
|
||||
require.Equal(t, msg.PublicSpendKey.Hex(), s.xmrmakerPublicSpendKey.Hex())
|
||||
require.Equal(t, msg.PrivateViewKey.Hex(), s.xmrmakerPrivateViewKey.Hex())
|
||||
|
||||
|
||||
@@ -68,8 +68,8 @@ func TestInstance_createOngoingSwap(t *testing.T) {
|
||||
StartNumber: big.NewInt(1),
|
||||
SwapCreatorAddr: inst.backend.SwapCreatorAddr(),
|
||||
Swap: &contracts.SwapCreatorSwap{
|
||||
Timeout0: big.NewInt(1),
|
||||
Timeout1: big.NewInt(2),
|
||||
Timeout1: big.NewInt(1),
|
||||
Timeout2: big.NewInt(2),
|
||||
},
|
||||
}, nil)
|
||||
rdb.EXPECT().GetSwapPrivateKey(s.OfferID).Return(
|
||||
|
||||
@@ -119,7 +119,7 @@ func (s *swapState) handleSendKeysMessage(msg *message.SendKeysMessage) (common.
|
||||
}
|
||||
|
||||
// start goroutine to check that XMRMaker locks before t_0
|
||||
go s.runT0ExpirationHandler()
|
||||
go s.runT1ExpirationHandler()
|
||||
|
||||
// start goroutine to check for xmr being locked
|
||||
go s.checkForXMRLock()
|
||||
@@ -185,20 +185,20 @@ func (s *swapState) checkForXMRLock() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *swapState) runT0ExpirationHandler() {
|
||||
defer log.Debugf("returning from runT0ExpirationHandler")
|
||||
func (s *swapState) runT1ExpirationHandler() {
|
||||
defer log.Debugf("returning from runT1ExpirationHandler")
|
||||
|
||||
// TODO: this variable is so that we definitely refund before t0.
|
||||
// TODO: this variable is so that we definitely refund before t1.
|
||||
// Current algorithm is to trigger the timeout when only 15% of the allotted
|
||||
// time is remaining. If the block interval is 1 second on a test network and
|
||||
// and T0 is 7 seconds after swap creation, we need the refund to trigger more
|
||||
// than one second before the block with a timestamp exactly equal to T0 to
|
||||
// and T1 is 7 seconds after swap creation, we need the refund to trigger more
|
||||
// than one second before the block with a timestamp exactly equal to T1 to
|
||||
// satisfy the strictly less than requirement. 7s * 15% = 1.05s. 15% remaining
|
||||
// may be reasonable even with large timeouts on production networks, but more
|
||||
// research is needed.
|
||||
t0Delta := s.t1.Sub(s.t0) // time between swap start and T0 is equal to T1-T0
|
||||
deltaBeforeT0ToGiveUp := time.Duration(float64(t0Delta) * 0.15)
|
||||
deltaUntilGiveUp := time.Until(s.t0) - deltaBeforeT0ToGiveUp
|
||||
t1Delta := s.t2.Sub(s.t1) // time between swap start and T1 is equal to T2-T1
|
||||
deltaBeforeT1ToGiveUp := time.Duration(float64(t1Delta) * 0.15)
|
||||
deltaUntilGiveUp := time.Until(s.t1) - deltaBeforeT1ToGiveUp
|
||||
giveUpAndRefundTimer := time.NewTimer(deltaUntilGiveUp)
|
||||
defer giveUpAndRefundTimer.Stop() // don't wait for the timeout to garbage collect
|
||||
log.Debugf("time until refund: %vs", deltaUntilGiveUp.Seconds())
|
||||
@@ -209,7 +209,7 @@ func (s *swapState) runT0ExpirationHandler() {
|
||||
case <-s.xmrLockedCh:
|
||||
return
|
||||
case <-giveUpAndRefundTimer.C:
|
||||
log.Infof("approaching T0, attempting to refund ETH")
|
||||
log.Infof("approaching T1, attempting to refund ETH")
|
||||
event := newEventShouldRefund()
|
||||
s.eventCh <- event
|
||||
err := <-event.errCh
|
||||
@@ -234,24 +234,24 @@ func (s *swapState) handleNotifyXMRLock() error {
|
||||
return fmt.Errorf("failed to call Ready: %w", err)
|
||||
}
|
||||
|
||||
go s.runT1ExpirationHandler()
|
||||
go s.runT2ExpirationHandler()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *swapState) runT1ExpirationHandler() {
|
||||
log.Debugf("time until t1 (%s): %vs",
|
||||
s.t1.Format(common.TimeFmtSecs),
|
||||
time.Until(s.t1).Seconds(),
|
||||
func (s *swapState) runT2ExpirationHandler() {
|
||||
log.Debugf("time until t2 (%s): %vs",
|
||||
s.t2.Format(common.TimeFmtSecs),
|
||||
time.Until(s.t2).Seconds(),
|
||||
)
|
||||
|
||||
defer log.Debugf("returning from runT1ExpirationHandler")
|
||||
defer log.Debugf("returning from runT2ExpirationHandler")
|
||||
|
||||
waitCtx, waitCtxCancel := context.WithCancel(context.Background())
|
||||
defer waitCtxCancel() // Unblock WaitForTimestamp if still running when we exit
|
||||
|
||||
waitCh := make(chan error)
|
||||
go func() {
|
||||
waitCh <- s.ETHClient().WaitForTimestamp(waitCtx, s.t1)
|
||||
waitCh <- s.ETHClient().WaitForTimestamp(waitCtx, s.t2)
|
||||
close(waitCh)
|
||||
}()
|
||||
|
||||
@@ -264,15 +264,15 @@ func (s *swapState) runT1ExpirationHandler() {
|
||||
if err != nil {
|
||||
// TODO: Do we propagate this error? If we retry, the logic should probably be inside
|
||||
// WaitForTimestamp. (#162)
|
||||
log.Errorf("failure waiting for T1 timeout: %s", err)
|
||||
log.Errorf("failure waiting for T2 timeout: %s", err)
|
||||
return
|
||||
}
|
||||
s.handleT1Expired()
|
||||
s.handleT2Expired()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *swapState) handleT1Expired() {
|
||||
log.Debugf("handling T1")
|
||||
func (s *swapState) handleT2Expired() {
|
||||
log.Debugf("handling T2")
|
||||
event := newEventShouldRefund()
|
||||
s.eventCh <- event
|
||||
err := <-event.errCh
|
||||
|
||||
@@ -72,7 +72,7 @@ type swapState struct {
|
||||
// swap contract and timeouts in it; set once contract is deployed
|
||||
contractSwapID [32]byte
|
||||
contractSwap *contracts.SwapCreatorSwap
|
||||
t0, t1 time.Time
|
||||
t1, t2 time.Time
|
||||
|
||||
// tracks the state of the swap
|
||||
nextExpectedEvent EventType
|
||||
@@ -86,9 +86,9 @@ type swapState struct {
|
||||
eventCh chan Event
|
||||
// channel for `Claimed` logs seen on-chain
|
||||
logClaimedCh chan ethtypes.Log
|
||||
// signals the t0 expiration handler to return
|
||||
xmrLockedCh chan struct{}
|
||||
// signals the t1 expiration handler to return
|
||||
xmrLockedCh chan struct{}
|
||||
// signals the t2 expiration handler to return
|
||||
claimedCh chan struct{}
|
||||
// signals to the creator xmrmaker instance that it can delete this swap
|
||||
done chan struct{}
|
||||
@@ -192,7 +192,7 @@ func newSwapStateFromOngoing(
|
||||
return nil, errContractAddrMismatch(ethSwapInfo.SwapCreatorAddr.String())
|
||||
}
|
||||
|
||||
s.setTimeouts(ethSwapInfo.Swap.Timeout0, ethSwapInfo.Swap.Timeout1)
|
||||
s.setTimeouts(ethSwapInfo.Swap.Timeout1, ethSwapInfo.Swap.Timeout2)
|
||||
s.privkeys = sk
|
||||
s.pubkeys = sk.PublicKeyPair()
|
||||
s.contractSwapID = ethSwapInfo.SwapID
|
||||
@@ -406,7 +406,7 @@ func (s *swapState) exit() error {
|
||||
//
|
||||
// for EventETHClaimed, the XMR has been locked, but the
|
||||
// ETH hasn't been claimed, but the contract has been set to ready.
|
||||
// we should also refund in this case, since we might be past t1.
|
||||
// we should also refund in this case, since we might be past t2.
|
||||
receipt, err := s.tryRefund()
|
||||
if err != nil {
|
||||
if errors.Is(err, errRefundSwapCompleted) || strings.Contains(err.Error(), revertSwapCompleted) {
|
||||
@@ -469,48 +469,48 @@ func (s *swapState) tryRefund() (*ethtypes.Receipt, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("tryRefund isReady=%v untilT0=%vs untilT1=%vs",
|
||||
isReady, s.t0.Sub(ts).Seconds(), s.t1.Sub(ts).Seconds())
|
||||
log.Debugf("tryRefund isReady=%v untilT1=%vs untilT2=%vs",
|
||||
isReady, s.t1.Sub(ts).Seconds(), s.t2.Sub(ts).Seconds())
|
||||
|
||||
if ts.Before(s.t0) && !isReady {
|
||||
if ts.Before(s.t1) && !isReady {
|
||||
receipt, err := s.refund() //nolint:govet
|
||||
// TODO: Have refund() return errors that we can use errors.Is to check against
|
||||
if err == nil {
|
||||
return receipt, nil
|
||||
}
|
||||
|
||||
// There is a small, but non-zero chance that our transaction gets placed in a block that is after T0
|
||||
// even though the current block is before T0. In this case, the transaction will be reverted, the
|
||||
// gas fee is lost, but we can wait until T1 and try again.
|
||||
// There is a small, but non-zero chance that our transaction gets placed in a block that is after T1
|
||||
// even though the current block is before T1. In this case, the transaction will be reverted, the
|
||||
// gas fee is lost, but we can wait until T2 and try again.
|
||||
log.Warnf("first refund attempt failed: err=%s", err)
|
||||
}
|
||||
|
||||
if ts.After(s.t1) {
|
||||
if ts.After(s.t2) {
|
||||
return s.refund()
|
||||
}
|
||||
|
||||
// the contract is "ready", so we can't do anything until
|
||||
// the counterparty claims or until t1 passes.
|
||||
// the counterparty claims or until t2 passes.
|
||||
//
|
||||
// we let the runT1ExpirationHandler() routine continue to run and read
|
||||
// we let the runT2ExpirationHandler() routine continue to run and read
|
||||
// from s.eventCh for EventShouldRefund or EventETHClaimed.
|
||||
// (since this function is called from inside the event handler routine,
|
||||
// it won't handle those events while this function is executing.)
|
||||
log.Infof("waiting until time %s to refund", s.t1)
|
||||
log.Infof("waiting until time %s to refund", s.t2)
|
||||
|
||||
waitCtx, waitCtxCancel := context.WithCancel(s.ctx)
|
||||
defer waitCtxCancel()
|
||||
|
||||
waitCh := make(chan error)
|
||||
go func() {
|
||||
waitCh <- s.ETHClient().WaitForTimestamp(waitCtx, s.t1)
|
||||
waitCh <- s.ETHClient().WaitForTimestamp(waitCtx, s.t2)
|
||||
close(waitCh)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-s.eventCh:
|
||||
log.Debugf("got event %s while waiting for T1", event.Type())
|
||||
log.Debugf("got event %s while waiting for T2", event.Type())
|
||||
switch event.(type) {
|
||||
case *EventShouldRefund:
|
||||
return s.refund()
|
||||
@@ -521,11 +521,11 @@ func (s *swapState) tryRefund() (*ethtypes.Receipt, error) {
|
||||
case *EventExit:
|
||||
// do nothing, we're already exiting
|
||||
default:
|
||||
panic(fmt.Sprintf("got unexpected event while waiting for Claimed/T1: %s", event.Type()))
|
||||
panic(fmt.Sprintf("got unexpected event while waiting for Claimed/T2: %s", event.Type()))
|
||||
}
|
||||
case err = <-waitCh:
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to wait for T1: %w", err)
|
||||
return nil, fmt.Errorf("failed to wait for T2: %w", err)
|
||||
}
|
||||
|
||||
return s.refund()
|
||||
@@ -533,11 +533,11 @@ func (s *swapState) tryRefund() (*ethtypes.Receipt, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *swapState) setTimeouts(t0, t1 *big.Int) {
|
||||
s.t0 = time.Unix(t0.Int64(), 0)
|
||||
func (s *swapState) setTimeouts(t1, t2 *big.Int) {
|
||||
s.t1 = time.Unix(t1.Int64(), 0)
|
||||
s.info.Timeout0 = &s.t0
|
||||
s.t2 = time.Unix(t2.Int64(), 0)
|
||||
s.info.Timeout1 = &s.t1
|
||||
s.info.Timeout2 = &s.t2
|
||||
}
|
||||
|
||||
func (s *swapState) generateAndSetKeys() error {
|
||||
@@ -621,10 +621,10 @@ func (s *swapState) lockAsset() (*ethtypes.Receipt, error) {
|
||||
return nil, fmt.Errorf("swap ID not found in transaction receipt's logs: %w", err)
|
||||
}
|
||||
|
||||
var t0 *big.Int
|
||||
var t1 *big.Int
|
||||
var t2 *big.Int
|
||||
for _, log := range receipt.Logs {
|
||||
t0, t1, err = contracts.GetTimeoutsFromLog(log)
|
||||
t1, t2, err = contracts.GetTimeoutsFromLog(log)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
@@ -634,15 +634,15 @@ func (s *swapState) lockAsset() (*ethtypes.Receipt, error) {
|
||||
}
|
||||
|
||||
s.fundsLocked = true
|
||||
s.setTimeouts(t0, t1)
|
||||
s.setTimeouts(t1, t2)
|
||||
|
||||
s.contractSwap = &contracts.SwapCreatorSwap{
|
||||
Owner: s.ETHClient().Address(),
|
||||
Claimer: s.xmrmakerAddress,
|
||||
PubKeyClaim: cmtXMRMaker,
|
||||
PubKeyRefund: cmtXMRTaker,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: ethcommon.Address(s.info.EthAsset),
|
||||
Value: s.providedAmount.BigInt(),
|
||||
Nonce: nonce,
|
||||
|
||||
@@ -227,13 +227,13 @@ func TestSwapState_HandleProtocolMessage_SendKeysMessage(t *testing.T) {
|
||||
|
||||
resp := net.LastSentMessage()
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, s.SwapTimeout(), s.t1.Sub(s.t0))
|
||||
require.Equal(t, s.SwapTimeout(), s.t2.Sub(s.t1))
|
||||
require.Equal(t, xmrmakerKeysAndProof.PublicKeyPair.SpendKey().String(), s.xmrmakerPublicSpendKey.String())
|
||||
require.Equal(t, xmrmakerKeysAndProof.PrivateKeyPair.ViewKey().String(), s.xmrmakerPrivateViewKey.String())
|
||||
}
|
||||
|
||||
// test the case where XMRTaker deploys and locks her eth, but XMRMaker never locks his monero.
|
||||
// XMRTaker should call refund before the timeout t0.
|
||||
// XMRTaker should call refund before the timeout t1.
|
||||
func TestSwapState_HandleProtocolMessage_SendKeysMessage_Refund(t *testing.T) {
|
||||
s, net := newTestSwapStateAndNet(t)
|
||||
defer s.cancel()
|
||||
@@ -247,19 +247,19 @@ func TestSwapState_HandleProtocolMessage_SendKeysMessage_Refund(t *testing.T) {
|
||||
resp := net.LastSentMessage()
|
||||
require.NotNil(t, resp)
|
||||
require.Equal(t, message.NotifyETHLockedType, resp.Type())
|
||||
require.Equal(t, s.SwapTimeout(), s.t1.Sub(s.t0))
|
||||
require.Equal(t, s.SwapTimeout(), s.t2.Sub(s.t1))
|
||||
require.Equal(t, xmrmakerKeysAndProof.PublicKeyPair.SpendKey().String(), s.xmrmakerPublicSpendKey.String())
|
||||
require.Equal(t, xmrmakerKeysAndProof.PrivateKeyPair.ViewKey().String(), s.xmrmakerPrivateViewKey.String())
|
||||
|
||||
// ensure we refund before t0
|
||||
// ensure we refund before t1
|
||||
for status := range s.info.StatusCh() {
|
||||
if status == types.CompletedRefund {
|
||||
// check this is before t0
|
||||
// check this is before t1
|
||||
// TODO: remove the 10-second buffer, this is needed for now
|
||||
// because the exact refund time isn't stored, and the time
|
||||
// between the refund happening and this line being called
|
||||
// causes it to fail
|
||||
require.Greater(t, s.t0.Add(time.Second*10), time.Now())
|
||||
require.Greater(t, s.t1.Add(time.Second*10), time.Now())
|
||||
break
|
||||
} else if !status.IsOngoing() {
|
||||
t.Fatalf("got wrong exit status %s, expected CompletedRefund", status)
|
||||
@@ -315,7 +315,7 @@ func TestSwapState_NotifyXMRLock(t *testing.T) {
|
||||
}
|
||||
|
||||
// test the case where the monero is locked, but XMRMaker never claims.
|
||||
// XMRTaker should call refund after the timeout t1.
|
||||
// XMRTaker should call refund after the timeout t2.
|
||||
func TestSwapState_NotifyXMRLock_Refund(t *testing.T) {
|
||||
s := newTestSwapState(t)
|
||||
defer s.cancel()
|
||||
@@ -348,8 +348,8 @@ func TestSwapState_NotifyXMRLock_Refund(t *testing.T) {
|
||||
|
||||
for status := range s.info.StatusCh() {
|
||||
if status == types.CompletedRefund {
|
||||
// check this is after t1
|
||||
require.Less(t, s.t1, time.Now())
|
||||
// check this is after t2
|
||||
require.Less(t, s.t2, time.Now())
|
||||
break
|
||||
} else if !status.IsOngoing() {
|
||||
t.Fatalf("got wrong exit status %s, expected CompletedRefund", status)
|
||||
|
||||
@@ -43,8 +43,8 @@ func createTestSwap(claimer ethcommon.Address) *contracts.SwapCreatorSwap {
|
||||
Claimer: claimer,
|
||||
PubKeyClaim: [32]byte{0x1},
|
||||
PubKeyRefund: [32]byte{0x1},
|
||||
Timeout0: big.NewInt(time.Now().Add(30 * time.Minute).Unix()),
|
||||
Timeout1: big.NewInt(time.Now().Add(60 * time.Minute).Unix()),
|
||||
Timeout1: big.NewInt(time.Now().Add(30 * time.Minute).Unix()),
|
||||
Timeout2: big.NewInt(time.Now().Add(60 * time.Minute).Unix()),
|
||||
Asset: ethcommon.Address(types.EthAssetETH),
|
||||
Value: big.NewInt(1e18),
|
||||
Nonce: big.NewInt(1),
|
||||
|
||||
@@ -55,8 +55,8 @@ func Test_ValidateAndSendTransaction(t *testing.T) {
|
||||
swapCreator, err := contracts.NewSwapCreator(swapCreatorAddr, ec.Raw())
|
||||
require.NoError(t, err)
|
||||
|
||||
testT0Timeout := big.NewInt(300) // 5 minutes
|
||||
testT1Timeout := testT0Timeout
|
||||
testT1Timeout := big.NewInt(300) // 5 minutes
|
||||
testT2Timeout := testT1Timeout
|
||||
|
||||
value := big.NewInt(9e16)
|
||||
nonce := big.NewInt(0)
|
||||
@@ -68,8 +68,8 @@ func Test_ValidateAndSendTransaction(t *testing.T) {
|
||||
cmt,
|
||||
refundKey,
|
||||
claimerAddr,
|
||||
testT0Timeout,
|
||||
testT1Timeout,
|
||||
testT2Timeout,
|
||||
types.EthAssetETH.Address(),
|
||||
value,
|
||||
nonce,
|
||||
@@ -85,7 +85,7 @@ func Test_ValidateAndSendTransaction(t *testing.T) {
|
||||
id, err := contracts.GetIDFromLog(receipt.Logs[logIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
t0, t1, err := contracts.GetTimeoutsFromLog(receipt.Logs[logIndex])
|
||||
t1, t2, err := contracts.GetTimeoutsFromLog(receipt.Logs[logIndex])
|
||||
require.NoError(t, err)
|
||||
|
||||
swap := contracts.SwapCreatorSwap{
|
||||
@@ -93,8 +93,8 @@ func Test_ValidateAndSendTransaction(t *testing.T) {
|
||||
Claimer: claimerAddr,
|
||||
PubKeyClaim: cmt,
|
||||
PubKeyRefund: refundKey,
|
||||
Timeout0: t0,
|
||||
Timeout1: t1,
|
||||
Timeout2: t2,
|
||||
Asset: types.EthAssetETH.Address(),
|
||||
Value: value,
|
||||
Nonce: nonce,
|
||||
|
||||
@@ -60,8 +60,8 @@ func TestValidateRelayerFee(t *testing.T) {
|
||||
Claimer: ethcommon.Address{},
|
||||
PubKeyClaim: [32]byte{},
|
||||
PubKeyRefund: [32]byte{},
|
||||
Timeout0: new(big.Int),
|
||||
Timeout1: new(big.Int),
|
||||
Timeout2: new(big.Int),
|
||||
Asset: ethcommon.Address{},
|
||||
Value: tc.value,
|
||||
Nonce: new(big.Int),
|
||||
|
||||
@@ -138,8 +138,8 @@ type OngoingSwap struct {
|
||||
Status types.Status `json:"status" validate:"required"`
|
||||
LastStatusUpdateTime time.Time `json:"lastStatusUpdateTime" validate:"required"`
|
||||
StartTime time.Time `json:"startTime" validate:"required"`
|
||||
Timeout0 *time.Time `json:"timeout0"`
|
||||
Timeout1 *time.Time `json:"timeout1"`
|
||||
Timeout2 *time.Time `json:"timeout2"`
|
||||
EstimatedTimeToCompletion time.Duration `json:"estimatedTimeToCompletion" validate:"required"`
|
||||
}
|
||||
|
||||
@@ -190,8 +190,8 @@ func (s *SwapService) GetOngoing(_ *http.Request, req *GetOngoingRequest, resp *
|
||||
swap.Status = info.Status
|
||||
swap.LastStatusUpdateTime = info.LastStatusUpdateTime
|
||||
swap.StartTime = info.StartTime
|
||||
swap.Timeout0 = info.Timeout0
|
||||
swap.Timeout1 = info.Timeout1
|
||||
swap.Timeout2 = info.Timeout2
|
||||
swap.EstimatedTimeToCompletion, err = estimatedTimeToCompletion(env, info.Status, info.LastStatusUpdateTime)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to estimate time to completion for swap %s: %w", info.OfferID, err)
|
||||
|
||||
@@ -385,11 +385,11 @@ func (s *IntegrationTestSuite) testRefundXMRTakerCancels(asset types.EthAsset) {
|
||||
require.Equal(s.T(), len(beforeResp.Offers), len(afterResp.Offers))
|
||||
}
|
||||
|
||||
// TestRefund_XMRMakerCancels_untilAfterT1 tests the case where XMRTaker and XMRMaker
|
||||
// TestRefund_XMRMakerCancels_untilAfterT2 tests the case where XMRTaker and XMRMaker
|
||||
// both lock their funds, but XMRMaker goes offline
|
||||
// until time t1 in the swap contract passes. This triggers XMRTaker to refund, which XMRMaker will then
|
||||
// until time t2 in the swap contract passes. This triggers XMRTaker to refund, which XMRMaker will then
|
||||
// "come online" to see, and he will then refund also.
|
||||
func (s *IntegrationTestSuite) TestRefund_XMRMakerCancels_untilAfterT1() {
|
||||
func (s *IntegrationTestSuite) TestRefund_XMRMakerCancels_untilAfterT2() {
|
||||
// Skipping test as it can't guarantee that the refund will happen before the swap completes
|
||||
// successfully: // https://github.com/athanorlabs/atomic-swap/issues/144
|
||||
s.T().Skip()
|
||||
@@ -398,7 +398,7 @@ func (s *IntegrationTestSuite) TestRefund_XMRMakerCancels_untilAfterT1() {
|
||||
}
|
||||
|
||||
// TestRefund_XMRMakerCancels_afterIsReady tests the case where XMRTaker and XMRMaker both lock their
|
||||
// funds, but XMRMaker goes offline until past isReady==true and t0, but comes online before t1. When
|
||||
// funds, but XMRMaker goes offline until past isReady==true and t1, but comes online before t2. When
|
||||
// XMRMaker comes back online, he should claim the ETH, causing XMRTaker to also claim the XMR.
|
||||
func (s *IntegrationTestSuite) TestRefund_XMRMakerCancels_afterIsReady() {
|
||||
// Skipping test as it can't guarantee that the refund will happen before the swap completes
|
||||
|
||||
Reference in New Issue
Block a user