diff --git a/client/asset/eth/eth.go b/client/asset/eth/eth.go index 07579b3b21..8eef685728 100644 --- a/client/asset/eth/eth.go +++ b/client/asset/eth/eth.go @@ -69,6 +69,7 @@ func init() { asset.Register(BipID, &Driver{}) registerToken(usdcTokenID, "The USDC Ethereum ERC20 token.") registerToken(usdtTokenID, "The USDT Ethereum ERC20 token.") + registerToken(maticTokenID, "The MATIC Ethereum ERC20 token.") } const ( @@ -124,9 +125,10 @@ const ( ) var ( - usdcTokenID, _ = dex.BipSymbolID("usdc.eth") - usdtTokenID, _ = dex.BipSymbolID("usdt.eth") - walletOpts = []*asset.ConfigOption{ + usdcTokenID, _ = dex.BipSymbolID("usdc.eth") + usdtTokenID, _ = dex.BipSymbolID("usdt.eth") + maticTokenID, _ = dex.BipSymbolID("matic.eth") + walletOpts = []*asset.ConfigOption{ { Key: "gasfeelimit", DisplayName: "Gas Fee Limit", @@ -5304,6 +5306,9 @@ func getFileCredentials(chain, path string, net dex.Network) (seed []byte, provi providers = append(providers, uri) } } + if len(providers) == 0 { + return nil, nil, fmt.Errorf("no providers in the file at %s for chain %s, network %s", path, chain, net) + } if net == dex.Simnet && len(providers) == 0 { u, _ := user.Current() switch chain { @@ -5382,12 +5387,13 @@ func quickNode(ctx context.Context, walletDir string, contractVer uint32, // waitForConfirmation waits for the specified transaction to have > 0 // confirmations. -func waitForConfirmation(ctx context.Context, cl ethFetcher, txHash common.Hash) error { +func waitForConfirmation(ctx context.Context, desc string, cl ethFetcher, txHash common.Hash, log dex.Logger) error { bestHdr, err := cl.bestHeader(ctx) if err != nil { return fmt.Errorf("error getting best header: %w", err) } ticker := time.NewTicker(stateUpdateTick) + lastReport := time.Now() defer ticker.Stop() for { select { @@ -5405,6 +5411,10 @@ func waitForConfirmation(ctx context.Context, cl ethFetcher, txHash common.Hash) if confs > 0 { return nil } + if time.Since(lastReport) > time.Second*30 { + log.Infof("Awaiting confirmations for %s tx %s", desc, txHash) + lastReport = time.Now() + } } case <-ctx.Done(): @@ -5837,7 +5847,8 @@ func (getGas) Estimate(ctx context.Context, net dex.Network, assetID, contractVe if err != nil { return fmt.Errorf("error sending fee reserves to approval client: %v", err) } - if err = waitForConfirmation(ctx, approvalClient, tx.Hash()); err != nil { + log.Infof("Funded approval client gas with %s in transaction %s", wParams.UnitInfo.FormatAtoms(feePreload), tx.Hash()) + if err = waitForConfirmation(ctx, "approval client fee funding", approvalClient, tx.Hash(), log); err != nil { return fmt.Errorf("error waiting for approval fee funding tx: %w", err) } @@ -5949,7 +5960,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t if err != nil { return fmt.Errorf("error estimating approve gas: %w", err) } - if err = waitForConfirmation(ctx, cl, tx.Hash()); err != nil { + if err = waitForConfirmation(ctx, "approval", cl, tx.Hash(), log); err != nil { return fmt.Errorf("error waiting for approve transaction: %w", err) } receipt, _, err := cl.transactionAndReceipt(ctx, tx.Hash()) @@ -5988,7 +5999,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t if err != nil { return fmt.Errorf("transfer error: %w", err) } - if err = waitForConfirmation(ctx, cl, transferTx.Hash()); err != nil { + if err = waitForConfirmation(ctx, "transfer", cl, transferTx.Hash(), log); err != nil { return fmt.Errorf("error waiting for transfer tx: %w", err) } receipt, _, err := cl.transactionAndReceipt(ctx, transferTx.Hash()) @@ -6034,7 +6045,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t if err != nil { return fmt.Errorf("initiate error for %d swaps: %v", n, err) } - if err = waitForConfirmation(ctx, cl, tx.Hash()); err != nil { + if err = waitForConfirmation(ctx, "init", cl, tx.Hash(), log); err != nil { return fmt.Errorf("error waiting for init tx to be mined: %w", err) } receipt, _, err := cl.transactionAndReceipt(ctx, tx.Hash()) @@ -6076,7 +6087,7 @@ func getGasEstimates(ctx context.Context, cl, acl ethFetcher, c contractor, ac t if err != nil { return fmt.Errorf("redeem error for %d swaps: %v", n, err) } - if err = waitForConfirmation(ctx, cl, tx.Hash()); err != nil { + if err = waitForConfirmation(ctx, "redeem", cl, tx.Hash(), log); err != nil { return fmt.Errorf("error waiting for redeem tx to be mined: %w", err) } receipt, _, err = cl.transactionAndReceipt(ctx, tx.Hash()) diff --git a/client/webserver/site/src/img/coins/matic.png b/client/webserver/site/src/img/coins/matic.png new file mode 100644 index 0000000000..ca981846d5 Binary files /dev/null and b/client/webserver/site/src/img/coins/matic.png differ diff --git a/client/webserver/site/src/js/doc.ts b/client/webserver/site/src/js/doc.ts index 01f1579292..7be2a2d583 100644 --- a/client/webserver/site/src/js/doc.ts +++ b/client/webserver/site/src/js/doc.ts @@ -31,6 +31,7 @@ const BipIDs: Record = { 60: 'eth', 60001: 'usdc.eth', 60002: 'usdt.eth', + 60003: 'matic.eth', 136: 'firo', 133: 'zec', 966: 'polygon', diff --git a/dex/bip-id.go b/dex/bip-id.go index f173800d1e..2459ba2f9c 100644 --- a/dex/bip-id.go +++ b/dex/bip-id.go @@ -607,6 +607,7 @@ var bipIDs = map[uint32]string{ // Ethereum reserved token range 60000-60999 60001: "usdc.eth", 60002: "usdt.eth", + 60003: "matic.eth", // Old MATIC token on Ethereum, not POL token // END Ethereum reserved token range 65536: "keth", 88888: "ryo[c0ban]", diff --git a/dex/fiatrates/fiatrates.go b/dex/fiatrates/fiatrates.go index ac7754f374..a3362a841a 100644 --- a/dex/fiatrates/fiatrates.go +++ b/dex/fiatrates/fiatrates.go @@ -30,8 +30,9 @@ type CoinpaprikaAsset struct { func parseCoinpapNameSymbol(name, symbol string) (string, string) { parts := strings.Split(symbol, ".") + network := symbol if len(parts) == 2 { - symbol = parts[0] + symbol, network = parts[0], parts[1] } switch symbol { case "usdc": @@ -41,6 +42,11 @@ func parseCoinpapNameSymbol(name, symbol string) (string, string) { name = "polygon" case "weth": name = "weth" + case "matic": + switch network { + case "eth": + symbol, name = "matic", "polygon" + } } return name, symbol } diff --git a/dex/networks/eth/params.go b/dex/networks/eth/params.go index 7f5211ff11..b78bb2d930 100644 --- a/dex/networks/eth/params.go +++ b/dex/networks/eth/params.go @@ -289,8 +289,11 @@ type Redemption struct { SecretHash [32]byte } -var usdcTokenID, _ = dex.BipSymbolID("usdc.eth") -var usdtTokenID, _ = dex.BipSymbolID("usdt.eth") +var ( + usdcTokenID, _ = dex.BipSymbolID("usdc.eth") + usdtTokenID, _ = dex.BipSymbolID("usdt.eth") + maticTokenID, _ = dex.BipSymbolID("matic.eth") // old matic 0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0 +) // Gases lists the expected gas required for various DEX and wallet operations. type Gases struct { diff --git a/dex/networks/eth/tokens.go b/dex/networks/eth/tokens.go index f816ddcaba..659cf7024d 100644 --- a/dex/networks/eth/tokens.go +++ b/dex/networks/eth/tokens.go @@ -278,6 +278,65 @@ var Tokens = map[uint32]*Token{ }, }, }, + maticTokenID: { + Token: &dex.Token{ + ParentID: EthBipID, + Name: "MATIC", + UnitInfo: dex.UnitInfo{ + AtomicUnit: "gwei", + Conventional: dex.Denomination{ + Unit: "MATIC", + ConversionFactor: 1e9, + }, + Alternatives: []dex.Denomination{ + { + Unit: "Szabos", + ConversionFactor: 1e6, + }, + { + Unit: "Finneys", + ConversionFactor: 1e3, + }, + }, + FeeRateDenom: "gas", + }, + }, + NetTokens: map[dex.Network]*NetToken{ + dex.Mainnet: { + Address: common.HexToAddress("0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0"), // https://etherscan.io/address/0x7d1afa7b718fb893db30a3abc0cfc608aacfebb0 + SwapContracts: map[uint32]*SwapContract{ + 0: { + // swap contract: https://etherscan.io/address/0x9572727D79FD074D3Ac731c584bf51dCF7459C12 + Address: common.HexToAddress("0x9572727D79FD074D3Ac731c584bf51dCF7459C12"), + Gas: Gases{ + // Results from client's GetGasEstimates. + // + // First swap used 178058 gas Recommended Gases.Swap = 231475 + // 1 additional swaps averaged 112627 gas each. Recommended Gases.SwapAdd = 146415 + // 178058 290685] + // First redeem used 67456 gas. Recommended Gases.Redeem = 87692 + // 1 additional redeems averaged 31641 gas each. recommended Gases.RedeemAdd = 41133 + // 67456 99097] + // Average of 2 refunds: 52875. Recommended Gases.Refund = 68737 + // 52563 53187] + // Average of 2 approvals: 48764. Recommended Gases.Approve = 63393 + // 48764 48764] + // Average of 1 transfers: 53944. Recommended Gases.Transfer = 70127 + // 53944] + + Swap: 231_475, + SwapAdd: 146_415, + Redeem: 87_692, + RedeemAdd: 41_133, + Refund: 68_737, + Approve: 63_393, + Transfer: 70_127, + }, + }, + }, + }, + }, + }, } // MaybeReadSimnetAddrs attempts to read the info files generated by the eth diff --git a/server/asset/eth/eth.go b/server/asset/eth/eth.go index 9e18734d02..663345476b 100644 --- a/server/asset/eth/eth.go +++ b/server/asset/eth/eth.go @@ -66,6 +66,7 @@ func init() { registerToken(usdcID, 0) registerToken(usdtID, 0) + registerToken(maticID, 0) } const ( @@ -82,8 +83,9 @@ var ( SupportsDynamicTxFee: true, } - usdcID, _ = dex.BipSymbolID("usdc.eth") - usdtID, _ = dex.BipSymbolID("usdt.eth") + usdcID, _ = dex.BipSymbolID("usdc.eth") + usdtID, _ = dex.BipSymbolID("usdt.eth") + maticID, _ = dex.BipSymbolID("matic.eth") ) func networkToken(vToken *VersionedToken, net dex.Network) (netToken *dexeth.NetToken, contract *dexeth.SwapContract, err error) {