Files
atomic-swap/protocol/xmrtaker/net.go
2023-06-06 11:21:51 -05:00

127 lines
3.0 KiB
Go

// Copyright 2023 The AthanorLabs/atomic-swap Authors
// SPDX-License-Identifier: LGPL-3.0-only
package xmrtaker
import (
"github.com/cockroachdb/apd/v3"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/fatih/color"
"github.com/athanorlabs/atomic-swap/coins"
"github.com/athanorlabs/atomic-swap/common"
"github.com/athanorlabs/atomic-swap/common/types"
)
// Provides returns types.ProvidesETH
func (inst *Instance) Provides() coins.ProvidesCoin {
return coins.ProvidesETH
}
// InitiateProtocol is called when an RPC call is made from the user to take a swap.
// The input units are ether that we will provide.
func (inst *Instance) InitiateProtocol(
makerPeerID peer.ID,
providesAmount *apd.Decimal,
offer *types.Offer,
) (common.SwapState, error) {
maxDecimals := uint8(coins.NumEtherDecimals)
var token *coins.ERC20TokenInfo
if offer.EthAsset.IsToken() {
var err error
token, err = inst.backend.ETHClient().ERC20Info(inst.backend.Ctx(), offer.EthAsset.Address())
if err != nil {
return nil, err
}
maxDecimals = token.NumDecimals
}
err := coins.ValidatePositive("providesAmount", maxDecimals, providesAmount)
if err != nil {
return nil, err
}
providedAssetAmount := coins.NewEthAssetAmount(providesAmount, token)
providesAmtAsXMR, err := offer.ExchangeRate.ToXMR(providedAssetAmount)
if err != nil {
return nil, err
}
if providesAmtAsXMR.Cmp(offer.MinAmount) < 0 {
return nil, &errAmountProvidedTooLow{
providedAmtETH: providedAssetAmount,
providedAmtAsXMR: providesAmtAsXMR,
offerMinAmtXMR: offer.MinAmount,
exchangeRate: offer.ExchangeRate,
}
}
if providesAmtAsXMR.Cmp(offer.MaxAmount) > 0 {
return nil, &errAmountProvidedTooHigh{
providedAmtETH: providedAssetAmount,
providedAmtAsXMR: providesAmtAsXMR,
offerMaxAmtXMR: offer.MaxAmount,
exchangeRate: offer.ExchangeRate,
}
}
err = validateMinBalance(
inst.backend.Ctx(),
inst.backend.ETHClient(),
providesAmount,
offer.EthAsset,
)
if err != nil {
return nil, err
}
state, err := inst.initiate(makerPeerID, providedAssetAmount, offer.ExchangeRate, offer.EthAsset, offer.ID)
if err != nil {
return nil, err
}
return state, nil
}
func (inst *Instance) initiate(
makerPeerID peer.ID,
providesAmount coins.EthAssetAmount,
exchangeRate *coins.ExchangeRate,
ethAsset types.EthAsset,
offerID types.Hash,
) (*swapState, error) {
inst.swapMu.Lock()
defer inst.swapMu.Unlock()
if inst.swapStates[offerID] != nil {
return nil, errProtocolAlreadyInProgress
}
s, err := newSwapStateFromStart(
inst.backend,
makerPeerID,
offerID,
inst.noTransferBack,
providesAmount,
exchangeRate,
ethAsset,
)
if err != nil {
return nil, err
}
go func() {
<-s.done
inst.swapMu.Lock()
defer inst.swapMu.Unlock()
delete(inst.swapStates, offerID)
}()
log.Info(color.New(color.Bold).Sprintf("**initiated swap with offer ID=%s**", s.info.OfferID))
log.Info(color.New(color.Bold).Sprint("DO NOT EXIT THIS PROCESS OR THE SWAP MAY BE CANCELLED!"))
inst.swapStates[offerID] = s
return s, nil
}