Files
atomic-swap/rpc/swap.go
2022-06-13 20:50:10 -04:00

237 lines
5.5 KiB
Go

package rpc
import (
"encoding/hex"
"fmt"
"net/http"
"github.com/noot/atomic-swap/common"
"github.com/noot/atomic-swap/common/types"
)
// SwapService handles information about ongoing or past swaps.
type SwapService struct {
sm SwapManager
xmrtaker XMRTaker
xmrmaker XMRMaker
net Net
}
// NewSwapService ...
func NewSwapService(sm SwapManager, xmrtaker XMRTaker, xmrmaker XMRMaker, net Net) *SwapService {
return &SwapService{
sm: sm,
xmrtaker: xmrtaker,
xmrmaker: xmrmaker,
net: net,
}
}
// GetPastIDsResponse ...
type GetPastIDsResponse struct {
IDs []string `json:"ids"`
}
// GetPastIDs returns all past swap IDs
func (s *SwapService) GetPastIDs(_ *http.Request, _ *interface{}, resp *GetPastIDsResponse) error {
ids := s.sm.GetPastIDs()
resp.IDs = make([]string, len(ids))
for i := range resp.IDs {
resp.IDs[i] = ids[i].String()
}
return nil
}
// GetPastRequest ...
type GetPastRequest struct {
OfferID string `json:"offerID"`
}
// GetPastResponse ...
type GetPastResponse struct {
Provided types.ProvidesCoin `json:"provided"`
ProvidedAmount float64 `json:"providedAmount"`
ReceivedAmount float64 `json:"receivedAmount"`
ExchangeRate types.ExchangeRate `json:"exchangeRate"`
Status string `json:"status"`
}
// GetPast returns information about a past swap, given its ID.
func (s *SwapService) GetPast(_ *http.Request, req *GetPastRequest, resp *GetPastResponse) error {
offerID, err := offerIDStringToHash(req.OfferID)
if err != nil {
return err
}
info := s.sm.GetPastSwap(offerID)
if info == nil {
return errNoSwapWithID
}
resp.Provided = info.Provides()
resp.ProvidedAmount = info.ProvidedAmount()
resp.ReceivedAmount = info.ReceivedAmount()
resp.ExchangeRate = info.ExchangeRate()
resp.Status = info.Status().String()
return nil
}
// GetOngoingResponse ...
type GetOngoingResponse struct {
Provided types.ProvidesCoin `json:"provided"`
ProvidedAmount float64 `json:"providedAmount"`
ReceivedAmount float64 `json:"receivedAmount"`
ExchangeRate types.ExchangeRate `json:"exchangeRate"`
Status string `json:"status"`
}
// GetOngoingRequest ...
type GetOngoingRequest struct {
OfferID string `json:"id"`
}
// GetOngoing returns information about the ongoing swap, if there is one.
func (s *SwapService) GetOngoing(_ *http.Request, req *GetOngoingRequest, resp *GetOngoingResponse) error {
offerID, err := offerIDStringToHash(req.OfferID)
if err != nil {
return err
}
info := s.sm.GetOngoingSwap(offerID)
if info == nil {
return errNoOngoingSwap
}
resp.Provided = info.Provides()
resp.ProvidedAmount = info.ProvidedAmount()
resp.ReceivedAmount = info.ReceivedAmount()
resp.ExchangeRate = info.ExchangeRate()
resp.Status = info.Status().String()
return nil
}
// RefundRequest ...
type RefundRequest struct {
OfferID string `json:"id"`
}
// RefundResponse ...
type RefundResponse struct {
TxHash string `json:"transactionHash"`
}
// Refund refunds the ongoing swap if we are the ETH provider.
// TODO: remove in favour of swap_cancel?
func (s *SwapService) Refund(_ *http.Request, req *RefundRequest, resp *RefundResponse) error {
offerID, err := offerIDStringToHash(req.OfferID)
if err != nil {
return err
}
info := s.sm.GetOngoingSwap(offerID)
if info == nil {
return errNoOngoingSwap
}
if info.Provides() != types.ProvidesETH {
return errCannotRefund
}
txHash, err := s.xmrtaker.Refund(offerID)
if err != nil {
return fmt.Errorf("failed to refund: %w", err)
}
resp.TxHash = txHash.String()
return nil
}
// GetStageRequest ...
type GetStageRequest struct {
OfferID string `json:"id"`
}
// GetStageResponse ...
type GetStageResponse struct {
Stage string `json:"stage"`
Info string `json:"info"`
}
// GetStage returns the stage of the ongoing swap, if there is one.
func (s *SwapService) GetStage(_ *http.Request, req *GetStageRequest, resp *GetStageResponse) error {
offerID, err := offerIDStringToHash(req.OfferID)
if err != nil {
return err
}
info := s.sm.GetOngoingSwap(offerID)
if info == nil {
return errNoOngoingSwap
}
resp.Stage = info.Status().String()
resp.Info = info.Status().Info()
return nil
}
// GetOffersResponse ...
type GetOffersResponse struct {
Offers []*types.Offer `json:"offers"`
}
// GetOffers returns the currently available offers.
func (s *SwapService) GetOffers(_ *http.Request, _ *interface{}, resp *GetOffersResponse) error {
resp.Offers = s.xmrmaker.GetOffers()
return nil
}
// CancelRequest ...
type CancelRequest struct {
OfferID string `json:"id"`
}
// CancelResponse ...
type CancelResponse struct {
Status types.Status `json:"status"`
}
// Cancel attempts to cancel the currently ongoing swap, if there is one.
func (s *SwapService) Cancel(_ *http.Request, req *CancelRequest, resp *CancelResponse) error {
offerID, err := offerIDStringToHash(req.OfferID)
if err != nil {
return err
}
info := s.sm.GetOngoingSwap(offerID)
if info == nil {
return errNoOngoingSwap
}
var ss common.SwapState
switch info.Provides() {
case types.ProvidesETH:
ss = s.xmrtaker.GetOngoingSwapState(offerID)
case types.ProvidesXMR:
ss = s.xmrmaker.GetOngoingSwapState(offerID)
}
if err := ss.Exit(); err != nil {
return err
}
s.net.CloseProtocolStream(offerID)
info = s.sm.GetPastSwap(info.ID())
resp.Status = info.Status()
return nil
}
func offerIDStringToHash(s string) (types.Hash, error) {
offerIDBytes, err := hex.DecodeString(s)
if err != nil {
return types.Hash{}, err
}
var offerID types.Hash
copy(offerID[:], offerIDBytes)
return offerID, nil
}