Skip to content

Commit

Permalink
restore price feed (#494)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimalinux authored Jun 29, 2023
1 parent 485d133 commit 3b4870e
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 55 deletions.
20 changes: 12 additions & 8 deletions cmd/swapcli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,13 @@ func cliApp() *cli.App {
Flags: []cli.Flag{
&cli.StringFlag{
Name: flagMinAmount,
Aliases: []string{"min"},
Usage: "Minimum amount to be swapped, in XMR",
Required: true,
},
&cli.StringFlag{
Name: flagMaxAmount,
Aliases: []string{"max"},
Usage: "Maximum amount to be swapped, in XMR",
Required: true,
},
Expand All @@ -184,15 +186,16 @@ func cliApp() *cli.App {
},
&cli.BoolFlag{
Name: flagDetached,
Usage: "Exit immediately instead of subscribing to notifications about the swap's status",
Usage: "Exit immediately without subscribing to status notifications",
},
&cli.StringFlag{
Name: flagToken,
Usage: "Use to pass the ethereum ERC20 token address to receive instead of ETH",
Usage: "Ethereum ERC20 token address to receive instead of ETH",
},
&cli.BoolFlag{
Name: flagUseRelayer,
Usage: "Use the relayer even if the receiving account has enough ETH to claim",
Name: flagUseRelayer,
Usage: "Use the relayer even if the receiving account has enough ETH to claim",
Hidden: true, // useful for testing, but no clear end-user use case for the flag
},
swapdPortFlag,
},
Expand All @@ -215,12 +218,13 @@ func cliApp() *cli.App {
},
&cli.StringFlag{
Name: flagProvidesAmount,
Aliases: []string{"pa"},
Usage: "Amount of coin to send in the swap",
Required: true,
},
&cli.BoolFlag{
Name: flagDetached,
Usage: "Exit immediately instead of subscribing to notifications about the swap's status",
Usage: "Exit immediately without subscribing to status notifications",
},
swapdPortFlag,
},
Expand Down Expand Up @@ -251,7 +255,7 @@ func cliApp() *cli.App {
},
{
Name: "cancel",
Usage: "Cancel a ongoing swap if possible. Depending on the swap stage, this may not be possible.",
Usage: "Cancel ongoing swap, if possible at the current swap stage.",
Action: runCancel,
Flags: []cli.Flag{
&cli.StringFlag{
Expand Down Expand Up @@ -308,8 +312,8 @@ func cliApp() *cli.App {
},
},
{
Name: "suggested-exchange-rate",
Aliases: []string{"price-feed"},
Name: "price-feed",
Aliases: []string{"suggested-exchange-rate"},
Usage: "Returns the current mainnet exchange rate based on ETH/USD and XMR/USD price feeds.",
Action: runSuggestedExchangeRate,
Flags: []cli.Flag{swapdPortFlag},
Expand Down
9 changes: 5 additions & 4 deletions common/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ const (

// Ethereum chain IDs
const (
MainnetChainID = 1
SepoliaChainID = 11155111
GanacheChainID = 1337
HardhatChainID = 31337
MainnetChainID = 1
OpMainnetChainID = 10 // Optimism
SepoliaChainID = 11155111
GanacheChainID = 1337
HardhatChainID = 31337
)
38 changes: 14 additions & 24 deletions pricefeed/pricefeed.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,16 @@ import (
)

const (
// mainnetEndpoint is a mainnet ethereum endpoint, from
// https://chainlist.org/chain/1, which stagenet users get pointed at for
// price feeds, as Sepolia doesn't have an XMR feed. Mainnet users will use
// the same ethereum endpoint that they use for other swap transactions.
mainnetEndpoint = "https://eth-rpc.gateway.pokt.network"
// optimismEndpoint is an RPC endpoint for optimism mainnet. Note that we
// tried https://mainnet.optimism.io first, but it is severely rate limited
// to around 2 requests/second.
optimismEndpoint = "https://1rpc.io/op"

// https://data.chain.link/ethereum/mainnet/crypto-usd/eth-usd
chainlinkETHToUSDProxy = "0x5f4ec3df9cbd43714fe2740f5e3616155c5b8419"
// https://data.chain.link/optimism/mainnet/crypto-usd/eth-usd
chainlinkETHToUSDProxy = "0x13e3ee699d1909e989722e753853ae30b17e08c5"

// https://data.chain.link/ethereum/mainnet/crypto-usd/xmr-usd
chainlinkXMRToUSDProxy = "0xfa66458cce7dd15d8650015c4fce4d278271618f"
// https://data.chain.link/optimism/mainnet/crypto-usd/xmr-usd
chainlinkXMRToUSDProxy = "0x2a8d91686a048e98e6ccf1a89e82f40d14312672"
)

var (
Expand All @@ -47,19 +46,17 @@ type PriceFeed struct {
}

// GetETHUSDPrice returns the current ETH/USD price from the Chainlink oracle.
// It errors if the chain ID is not the Ethereum mainnet.
func GetETHUSDPrice(ctx context.Context, ec *ethclient.Client) (*PriceFeed, error) {
chainID, err := ec.ChainID(ctx)
if err != nil {
return nil, err
}

switch chainID.Uint64() {
case common.MainnetChainID:
case common.OpMainnetChainID:
// No extra work to do
case common.SepoliaChainID:
// Push stagenet/sepolia users to a mainnet endpoint
ec, err = ethclient.Dial(mainnetEndpoint)
case common.MainnetChainID, common.SepoliaChainID:
ec, err = ethclient.Dial(optimismEndpoint)
if err != nil {
return nil, err
}
Expand All @@ -78,25 +75,18 @@ func GetETHUSDPrice(ctx context.Context, ec *ethclient.Client) (*PriceFeed, erro
}

// GetXMRUSDPrice returns the current XMR/USD price from the Chainlink oracle.
// It errors if the chain ID is not the Ethereum mainnet.
func GetXMRUSDPrice(ctx context.Context, ec *ethclient.Client) (*PriceFeed, error) {
chainID, err := ec.ChainID(ctx)
if err != nil {
return nil, err
}

// Temporary hack to return a better error until the issue is resolved.
switch chainID.Uint64() {
case common.MainnetChainID, common.SepoliaChainID:
return nil, errors.New("https://github.com/AthanorLabs/atomic-swap/issues/492")
}

switch chainID.Uint64() {
case common.MainnetChainID:
case common.OpMainnetChainID:
// No extra work to do
case common.SepoliaChainID:
case common.MainnetChainID, common.SepoliaChainID:
// Push stagenet/sepolia users to a mainnet endpoint
ec, err = ethclient.Dial(mainnetEndpoint)
ec, err = ethclient.Dial(optimismEndpoint)
if err != nil {
return nil, err
}
Expand Down
48 changes: 29 additions & 19 deletions pricefeed/pricefeed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"testing"

"github.com/ethereum/go-ethereum/ethclient"
logging "github.com/ipfs/go-log/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand All @@ -15,18 +16,28 @@ import (
)

func init() {
logging.SetLogLevel("pricefeed", "debug")
_ = logging.SetLogLevel("pricefeed", "debug")
}

func TestGetETHUSDPrice_mainnet(t *testing.T) {
ec := tests.NewEthMainnetClient(t)

feed, err := GetETHUSDPrice(context.Background(), ec)
func newOptimismClient(t *testing.T) *ethclient.Client {
ec, err := ethclient.Dial(optimismEndpoint)
require.NoError(t, err)
t.Logf("%s is $%s (updated: %s)", feed.Description, feed.Price, feed.UpdatedAt)
assert.Equal(t, "ETH / USD", feed.Description)
assert.False(t, feed.Price.Negative)
assert.False(t, feed.Price.IsZero())
t.Cleanup(func() {
ec.Close()
})

return ec
}

func TestGetETHUSDPrice_nonDev(t *testing.T) {
for _, ec := range []*ethclient.Client{tests.NewEthSepoliaClient(t), newOptimismClient(t)} {
feed, err := GetETHUSDPrice(context.Background(), ec)
require.NoError(t, err)
t.Logf("%s is $%s (updated: %s)", feed.Description, feed.Price, feed.UpdatedAt)
assert.Equal(t, "ETH / USD", feed.Description)
assert.False(t, feed.Price.Negative)
assert.False(t, feed.Price.IsZero())
}
}

func TestGetETHUSDPrice_dev(t *testing.T) {
Expand All @@ -37,16 +48,15 @@ func TestGetETHUSDPrice_dev(t *testing.T) {
assert.Equal(t, "1234.12345678", feed.Price.String())
}

func TestGetXMRUSDPrice_mainnet(t *testing.T) {
t.Skip("Chainlink XMR price feed is down: https://github.com/AthanorLabs/atomic-swap/issues/492")
ec := tests.NewEthMainnetClient(t)

feed, err := GetXMRUSDPrice(context.Background(), ec)
require.NoError(t, err)
t.Logf("%s is $%s (updated: %s)", feed.Description, feed.Price, feed.UpdatedAt)
assert.Equal(t, "XMR / USD", feed.Description)
assert.False(t, feed.Price.Negative)
assert.False(t, feed.Price.IsZero())
func TestGetXMRUSDPrice_nonDev(t *testing.T) {
for _, ec := range []*ethclient.Client{tests.NewEthSepoliaClient(t), newOptimismClient(t)} {
feed, err := GetXMRUSDPrice(context.Background(), ec)
require.NoError(t, err)
t.Logf("%s is $%s (updated: %s)", feed.Description, feed.Price, feed.UpdatedAt)
assert.Equal(t, "XMR / USD", feed.Description)
assert.False(t, feed.Price.Negative)
assert.False(t, feed.Price.IsZero())
}
}

func TestGetXMRUSDPrice_dev(t *testing.T) {
Expand Down

0 comments on commit 3b4870e

Please sign in to comment.