Skip to content

Commit

Permalink
Merge pull request #12382 from brave/f/wallet/polygon-swap
Browse files Browse the repository at this point in the history
feat(wallet): add swap functionality on Polygon with 0x
  • Loading branch information
onyb authored Feb 26, 2022
2 parents a61fa01 + 8b796e5 commit 400c1e7
Show file tree
Hide file tree
Showing 43 changed files with 367 additions and 134 deletions.
10 changes: 6 additions & 4 deletions components/brave_wallet/browser/brave_wallet_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,8 @@ constexpr webui::LocalizedString kLocalizedStrings[] = {
{"braveWalletQueueRejectAll", IDS_BRAVE_WALLET_QUEUE_REJECT_ALL},
{"braveWalletSwapInsufficientBalance",
IDS_BRAVE_WALLET_SWAP_INSUFFICIENT_BALANCE},
{"braveWalletSwapInsufficientEthBalance",
IDS_BRAVE_WALLET_SWAP_INSUFFICIENT_ETH_BALANCE},
{"braveWalletSwapInsufficientFundsForGas",
IDS_BRAVE_WALLET_SWAP_INSUFFICIENT_FUNDS_FOR_GAS},
{"braveWalletSwapInsufficientLiquidity",
IDS_BRAVE_WALLET_SWAP_INSUFFICIENT_LIQUIDITY},
{"braveWalletSwapInsufficientAllowance",
Expand Down Expand Up @@ -621,15 +621,17 @@ constexpr webui::LocalizedString kLocalizedStrings[] = {
IDS_BRAVE_WALLET_TREZOR_SIGN_TYPED_DATA_ERROR},
};

// Swap constants
const char kRopstenSwapBaseAPIURL[] = "https://ropsten.api.0x.org/";
const char kRopstenBuyTokenPercentageFee[] = "0.00875";
// As of 22-02-2022, this address is controlled by @onyb.
const char kRopstenFeeRecipient[] =
"0xa92D461a9a988A7f11ec285d39783A637Fdd6ba4";

const char kPolygonSwapBaseAPIURL[] = "https://polygon.api.0x.org/";
const char kSwapBaseAPIURL[] = "https://api.0x.org/";
const char kBuyTokenPercentageFee[] = "0.00875";
const char kFeeRecipient[] = "0xbd9420A98a7Bd6B89765e5715e169481602D9c3d";
const char kAffiliateAddress[] = "0xbd9420A98a7Bd6B89765e5715e169481602D9c3d";

const int64_t kBlockTrackerDefaultTimeInSeconds = 20;

// Unstoppable domains record key for ethereum address.
Expand Down
18 changes: 11 additions & 7 deletions components/brave_wallet/browser/swap_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag() {

bool IsNetworkSupported(const std::string& chain_id) {
if (chain_id == brave_wallet::mojom::kRopstenChainId ||
chain_id == brave_wallet::mojom::kMainnetChainId) {
chain_id == brave_wallet::mojom::kMainnetChainId ||
chain_id == brave_wallet::mojom::kPolygonMainnetChainId) {
return true;
}

Expand Down Expand Up @@ -116,10 +117,7 @@ void SwapService::SetBaseURLForTest(const GURL& base_url_for_test) {
// static
std::string SwapService::GetFee(const std::string& chain_id) {
std::string fee;

if (chain_id == brave_wallet::mojom::kRopstenChainId) {
fee = brave_wallet::kRopstenBuyTokenPercentageFee;
} else if (chain_id == brave_wallet::mojom::kMainnetChainId) {
if (IsNetworkSupported(chain_id)) {
fee = brave_wallet::kBuyTokenPercentageFee;
}

Expand All @@ -134,6 +132,8 @@ std::string SwapService::GetBaseSwapURL(const std::string& chain_id) {
url = brave_wallet::kRopstenSwapBaseAPIURL;
} else if (chain_id == brave_wallet::mojom::kMainnetChainId) {
url = brave_wallet::kSwapBaseAPIURL;
} else if (chain_id == brave_wallet::mojom::kPolygonMainnetChainId) {
url = brave_wallet::kPolygonSwapBaseAPIURL;
}

return url;
Expand All @@ -143,9 +143,12 @@ std::string SwapService::GetBaseSwapURL(const std::string& chain_id) {
std::string SwapService::GetFeeRecipient(const std::string& chain_id) {
std::string feeRecipient;

// For easy testability on test networks, we use an address different from
// the production multisig address.
if (chain_id == brave_wallet::mojom::kRopstenChainId) {
feeRecipient = brave_wallet::kRopstenFeeRecipient;
} else if (chain_id == brave_wallet::mojom::kMainnetChainId) {
} else if (chain_id == brave_wallet::mojom::kMainnetChainId ||
chain_id == brave_wallet::mojom::kPolygonMainnetChainId) {
feeRecipient = brave_wallet::kFeeRecipient;
}

Expand All @@ -156,7 +159,8 @@ std::string SwapService::GetFeeRecipient(const std::string& chain_id) {
std::string SwapService::GetAffiliateAddress(const std::string& chain_id) {
std::string affiliateAddress;

if (chain_id == brave_wallet::mojom::kMainnetChainId) {
if (chain_id == brave_wallet::mojom::kMainnetChainId ||
chain_id == brave_wallet::mojom::kPolygonMainnetChainId) {
affiliateAddress = brave_wallet::kAffiliateAddress;
}

Expand Down
16 changes: 16 additions & 0 deletions components/brave_wallet/browser/swap_service_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,21 @@ TEST_F(SwapServiceUnitTest, GetSwapConfigurationMainnet) {
SwapService::GetAffiliateAddress(mojom::kMainnetChainId));
}

TEST_F(SwapServiceUnitTest, GetSwapConfigurationPolygonMainnet) {
std::string swap_api_url = "https://polygon.api.0x.org/";
std::string buy_token_percantage_fee = "0.00875";
std::string fee_recipient = "0xbd9420A98a7Bd6B89765e5715e169481602D9c3d";
std::string affiliate_address = "0xbd9420A98a7Bd6B89765e5715e169481602D9c3d";
EXPECT_EQ(swap_api_url,
SwapService::GetBaseSwapURL(mojom::kPolygonMainnetChainId));
EXPECT_EQ(buy_token_percantage_fee,
SwapService::GetFee(mojom::kPolygonMainnetChainId));
EXPECT_EQ(fee_recipient,
SwapService::GetFeeRecipient(mojom::kPolygonMainnetChainId));
EXPECT_EQ(affiliate_address,
SwapService::GetAffiliateAddress(mojom::kPolygonMainnetChainId));
}

TEST_F(SwapServiceUnitTest, GetSwapConfigurationOtherNet) {
std::string swap_api_url;
std::string buy_token_percantage_fee;
Expand All @@ -322,6 +337,7 @@ TEST_F(SwapServiceUnitTest, GetSwapConfigurationOtherNet) {
TEST_F(SwapServiceUnitTest, IsSwapSupported) {
EXPECT_TRUE(IsSwapSupported(mojom::kMainnetChainId));
EXPECT_TRUE(IsSwapSupported(mojom::kRopstenChainId));
EXPECT_TRUE(IsSwapSupported(mojom::kPolygonMainnetChainId));
EXPECT_FALSE(IsSwapSupported(mojom::kRinkebyChainId));
EXPECT_FALSE(IsSwapSupported(""));
EXPECT_FALSE(IsSwapSupported("invalid chain_id"));
Expand Down
1 change: 1 addition & 0 deletions components/brave_wallet/common/brave_wallet.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ const string kRopstenChainId = "0x3";
const string kGoerliChainId = "0x5";
const string kKovanChainId = "0x2a";
const string kLocalhostChainId = "0x539";
const string kPolygonMainnetChainId = "0x89";
const string kSolanaMainnet = "solana:0x65";
const string kSolanaTestnet = "solana:0x66";
const string kSolanaDevnet = "solana:0x67";
Expand Down
2 changes: 2 additions & 0 deletions components/brave_wallet_ui/assets/asset-icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ALGOIconUrl from './algo-asset-icon.svg'
import BNBIconUrl from './bnb-asset-icon.svg'
import BTCIconUrl from './btc-asset-icon.svg'
import ETHIconUrl from './eth-asset-icon.svg'
import MATICIconUrl from './matic-asset-icon.svg'
import ZRXIconUrl from './zrx-asset-icon.svg'
import SOLIconUrl from './sol-asset-icon.svg'
import FILECOINIconUrl from './filecoin-asset-icon.svg'
Expand All @@ -13,6 +14,7 @@ export {
BNBIconUrl,
BTCIconUrl,
ETHIconUrl,
MATICIconUrl,
ZRXIconUrl,
SOLIconUrl,
FILECOINIconUrl
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 16 additions & 11 deletions components/brave_wallet_ui/common/hooks/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@

import * as React from 'react'

// Constants
import {
BraveWallet,
WalletAccountType
} from '../../constants/types'
import { BAT, ETH } from '../../options/asset-options'

// Options
import { makeNetworkAsset } from '../../options/asset-options'

// Hooks
import usePricing from './pricing'
Expand All @@ -26,23 +29,25 @@ export default function useAssets (
) {
const { computeFiatAmount } = usePricing(spotPrices)
const getBalance = useBalance(selectedNetwork)
const nativeAsset = React.useMemo(
() => makeNetworkAsset(selectedNetwork),
[selectedNetwork]
)

const swapAssetOptions: BraveWallet.BlockchainToken[] = React.useMemo(() => {
return [
ETH,

...fullTokenList.filter((asset) => asset.symbol === 'BAT'),

nativeAsset,
...fullTokenList.filter((asset) => asset.symbol.toUpperCase() === 'BAT'),
...userVisibleTokensInfo
.filter(asset => !['BAT', 'ETH'].includes(asset.symbol)),

.filter(asset => !['BAT', nativeAsset.symbol.toUpperCase()].includes(asset.symbol.toUpperCase())),
...fullTokenList
.filter(asset => !['BAT', 'ETH'].includes(asset.symbol))
.filter(asset => !userVisibleTokensInfo.some(token => token.symbol === asset.symbol))
.filter(asset => !['BAT', nativeAsset.symbol.toUpperCase()].includes(asset.symbol.toUpperCase()))
.filter(asset => !userVisibleTokensInfo
.some(token => token.symbol.toUpperCase() === asset.symbol.toUpperCase()))
]
}, [fullTokenList, userVisibleTokensInfo])
}, [fullTokenList, userVisibleTokensInfo, nativeAsset])

const [buyAssetOptions, setBuyAssetOptions] = React.useState<BraveWallet.BlockchainToken[]>([BAT, ETH])
const [buyAssetOptions, setBuyAssetOptions] = React.useState<BraveWallet.BlockchainToken[]>([nativeAsset])

React.useEffect(() => {
getBuyAssets().then(tokens => {
Expand Down
12 changes: 6 additions & 6 deletions components/brave_wallet_ui/common/hooks/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ import { BraveWallet, WalletAccountType } from '../../constants/types'

export default function useBalance (network: BraveWallet.EthereumChain) {
return React.useCallback((account?: WalletAccountType, token?: BraveWallet.BlockchainToken) => {
if (!account) {
if (!account || !token) {
return ''
}

// Return native asset balance
if (!token || token.symbol.toLowerCase() === network.symbol.toLowerCase()) {
return account.balance
}

if (!account.tokenBalanceRegistry) {
return ''
}

// Return native asset balance
if (token.symbol.toLowerCase() === network.symbol.toLowerCase()) {
return account.balance
}

return (account.tokenBalanceRegistry || {})[token.contractAddress.toLowerCase()] || ''
}, [network])
}
20 changes: 20 additions & 0 deletions components/brave_wallet_ui/common/hooks/select-preset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,24 @@ describe('usePreset hook', () => {
expect(mockFunc.mock.calls.length).toBe(1)
expect(mockFunc.mock.calls[0][0]).toBe(expected)
})

it('should not do anything if send/swap asset is undefined', () => {
const mockOnSetFromAmount = jest.fn()
const mockOnSetSendAmount = jest.fn()

const { result: { current: calcPresetAmount } } = renderHook(() => usePreset(
mockAccount,
mockNetwork,
mockOnSetFromAmount,
mockOnSetSendAmount,
undefined,
undefined
))

calcPresetAmount('swap')(0.25)
expect(mockOnSetFromAmount.mock.calls.length).toBe(0)

calcPresetAmount('send')(0.25)
expect(mockOnSetSendAmount.mock.calls.length).toBe(0)
})
})
10 changes: 6 additions & 4 deletions components/brave_wallet_ui/common/hooks/select-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,23 @@ export default function usePreset (
selectedNetwork: BraveWallet.EthereumChain,
onSetFromAmount: (value: string) => void,
onSetSendAmount: (value: string) => void,
swapAsset: BraveWallet.BlockchainToken,
swapAsset?: BraveWallet.BlockchainToken,
sendAsset?: BraveWallet.BlockchainToken
) {
const getBalance = useBalance(selectedNetwork)

return (sendOrSwap: 'send' | 'swap') => (percent: number) => {
const selectedAsset = sendOrSwap === 'send' ? sendAsset : swapAsset
const decimals = selectedAsset?.decimals ?? 18
if (!selectedAsset) {
return
}

const assetBalance = getBalance(selectedAccount, selectedAsset) || '0'
const amountWrapped = new Amount(assetBalance).times(percent)

const formattedAmount = (percent === 1)
? amountWrapped.divideByDecimals(decimals).format()
: amountWrapped.divideByDecimals(decimals).format(6)
? amountWrapped.divideByDecimals(selectedAsset.decimals).format()
: amountWrapped.divideByDecimals(selectedAsset.decimals).format(6)

if (sendOrSwap === 'send') {
onSetSendAmount(formattedAmount)
Expand Down
8 changes: 4 additions & 4 deletions components/brave_wallet_ui/common/hooks/swap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,10 @@ describe('useSwap hook', () => {
// in the middle of a future update.
await waitForValueToChange(() => result.current.isSwapSupported)

// OK: Assert for swapValidationError to be 'insufficientEthBalance'.
// OK: Assert for swapValidationError to be 'insufficientFundsForGas'.
// KO: Test case times out.
await waitFor(() => {
expect(result.current.swapValidationError).toBe('insufficientEthBalance')
expect(result.current.swapValidationError).toBe('insufficientFundsForGas')
})
})

Expand Down Expand Up @@ -436,10 +436,10 @@ describe('useSwap hook', () => {
jest.advanceTimersByTime(1001)
})

// OK: Assert for swapValidationError to be 'insufficientEthBalance'.
// OK: Assert for swapValidationError to be 'insufficientFundsForGas'.
// KO: Test case times out.
await waitFor(() => {
expect(result.current.swapValidationError).toBe('insufficientEthBalance')
expect(result.current.swapValidationError).toBe('insufficientFundsForGas')
})

// OK: Assert for fromAmount to be '0.000000000000234561'.
Expand Down
Loading

0 comments on commit 400c1e7

Please sign in to comment.