feat(swap): add Swap v2 integration
This commit is contained in:
@@ -971,7 +971,72 @@ constexpr webui::LocalizedString kLocalizedStrings[] = {
|
||||
IDS_BRAVE_WALLET_ADD_ASSET_TOKEN_TAB_TITLE},
|
||||
{"braveWalletAddAssetNftTabTitle",
|
||||
IDS_BRAVE_WALLET_ADD_ASSET_NFT_TAB_TITLE},
|
||||
{"braveWalletNftFetchingError", IDS_BRAVE_WALLET_NFT_FETCHING_ERROR}};
|
||||
{"braveWalletNftFetchingError", IDS_BRAVE_WALLET_NFT_FETCHING_ERROR},
|
||||
|
||||
// Brave Swap
|
||||
{"braveSwap", IDS_BRAVE_SWAP},
|
||||
{"braveSwapReviewOrder", IDS_BRAVE_SWAP_REVIEW_ORDER},
|
||||
{"braveSwapApproveToken", IDS_BRAVE_SWAP_APPROVE_TOKEN},
|
||||
{"braveSwapInsufficientBalance", IDS_BRAVE_SWAP_INSUFFICIENT_BALANCE},
|
||||
{"braveSwapSelectToken", IDS_BRAVE_SWAP_SELECT_TOKEN},
|
||||
{"braveSwapHalf", IDS_BRAVE_SWAP_HALF},
|
||||
{"braveSwapMax", IDS_BRAVE_SWAP_MAX},
|
||||
{"braveSwapEnterAnAmount", IDS_BRAVE_SWAP_ENTER_AN_AMOUNT},
|
||||
{"braveSwapFindingPrice", IDS_BRAVE_SWAP_FINDING_PRICE},
|
||||
{"braveSwapBalance", IDS_BRAVE_SWAP_BALANCE},
|
||||
{"braveSwapSelectAToken", IDS_BRAVE_SWAP_SELECT_A_TOKEN},
|
||||
{"braveSwapShowTokensWithZeroBalances",
|
||||
IDS_BRAVE_SWAP_SHOW_TOKENS_WITH_ZERO_BALANCES},
|
||||
{"braveSwapHideTokensWithZeroBalances",
|
||||
IDS_BRAVE_SWAP_HIDE_TOKENS_WITH_ZERO_BALANCES},
|
||||
{"braveSwapSearchToken", IDS_BRAVE_SWAP_SEARCH_TOKEN},
|
||||
{"braveSwapOption", IDS_BRAVE_SWAP_OPTION},
|
||||
{"braveSwapRate", IDS_BRAVE_SWAP_RATE},
|
||||
{"braveSwapPriceImpact", IDS_BRAVE_SWAP_PRICE_IMPACT},
|
||||
{"braveSwapMinimumReceivedAfterSlippage",
|
||||
IDS_BRAVE_SWAP_MINIMUM_RECEIVED_AFTER_SLIPPAGE},
|
||||
{"braveSwapNetworkFee", IDS_BRAVE_SWAP_NETWORK_FEE},
|
||||
{"braveSwapBraveFee", IDS_BRAVE_SWAP_BRAVE_FEE},
|
||||
{"braveSwapFree", IDS_BRAVE_SWAP_FREE},
|
||||
{"braveSwapLiquidityProvider", IDS_BRAVE_SWAP_LIQUIDITY_PROVIDER},
|
||||
{"braveSwapSwapAndSend", IDS_BRAVE_SWAP_SWAP_AND_SEND},
|
||||
{"braveSwapNoExtraFees", IDS_BRAVE_SWAP_NO_EXTRA_FEES},
|
||||
{"braveSwapConfirmAddress", IDS_BRAVE_SWAP_CONFIRM_ADDRESS},
|
||||
{"braveSwapAddressInputePlaceholder",
|
||||
IDS_BRAVE_SWAP_ADDRESS_INPUT_PLACEHOLDER},
|
||||
{"braveSwapSelectAccount", IDS_BRAVE_SWAP_SELECT_ACCOUNT},
|
||||
{"braveSwapToAccount", IDS_BRAVE_SWAP_TO_ACCOUNT},
|
||||
{"braveSwapToAddress", IDS_BRAVE_SWAP_TO_ADDRESS},
|
||||
{"braveSwapSlow", IDS_BRAVE_SWAP_SLOW},
|
||||
{"braveSwapAverage", IDS_BRAVE_SWAP_AVERAGE},
|
||||
{"braveSwapFast", IDS_BRAVE_SWAP_FAST},
|
||||
{"braveSwapGwei", IDS_BRAVE_SWAP_GWEI},
|
||||
{"braveSwapSettings", IDS_BRAVE_SWAP_SETTINGS},
|
||||
{"braveSwapSlippageTolerance", IDS_BRAVE_SWAP_SLIPPAGE_TOLERANCE},
|
||||
{"braveSwapExchanges", IDS_BRAVE_SWAP_EXCHANGES},
|
||||
{"braveSwapDirectRouteTitle", IDS_BRAVE_SWAP_DIRECT_ROUTE_TITLE},
|
||||
{"braveSwapDirectRouteDescription",
|
||||
IDS_BRAVE_SWAP_DIRECT_ROUTE_DESCRIPTION},
|
||||
{"braveSwapNetworkFeeDescription", IDS_BRAVE_SWAP_NETWORK_FEE_DESCRIPTION},
|
||||
{"braveSwapCoinGeckoCheaper", IDS_BRAVE_SWAP_COINGECKO_CHEAPER},
|
||||
{"braveSwapCoinGeckoWithin", IDS_BRAVE_SWAP_COINGECKO_WITHIN},
|
||||
{"braveSwapCoinGeckoExpensive", IDS_BRAVE_SWAP_COINGECKO_EXPENSIVE},
|
||||
{"braveSwapAPI", IDS_BRAVE_SWAP_API},
|
||||
{"braveSwapName", IDS_BRAVE_SWAP_NAME},
|
||||
{"braveSwapConnectWallet", IDS_BRAVE_SWAP_CONNECT_WALLET},
|
||||
{"braveSwapDisconnectWallet", IDS_BRAVE_SWAP_DISCONNECT_WALLET},
|
||||
{"braveSwapSwitchNetwork", IDS_BRAVE_SWAP_SWITCH_NETWORK},
|
||||
{"braveSwapAdvanced", IDS_BRAVE_SWAP_ADVANCED},
|
||||
{"braveSwapAccounts", IDS_BRAVE_SWAP_ACCOUNTS},
|
||||
{"braveSwapWallet", IDS_BRAVE_SWAP_WALLET},
|
||||
{"braveSwapBest", IDS_BRAVE_SWAP_BEST},
|
||||
{"braveSwapHelpCenter", IDS_BRAVE_SWAP_HELP_CENTER},
|
||||
{"braveSwapPrivacyPolicy", IDS_BRAVE_SWAP_PRIVACY_POLICY},
|
||||
{"braveSwapPrivacyDescription", IDS_BRAVE_SWAP_PRIVACY_DESCRIPTION},
|
||||
{"braveSwapZeroXDisclaimer", IDS_BRAVE_SWAP_ZERO_EX_DISCLAIMER},
|
||||
{"braveSwapJupiterDisclaimer", IDS_BRAVE_SWAP_JUPITER_DISCLAIMER},
|
||||
{"braveSwapZeroXPrivacy", IDS_BRAVE_SWAP_ZERO_EX_PRIVACY},
|
||||
{"braveSwapJupiterPrivacy", IDS_BRAVE_SWAP_JUPITER_PRIVACY}};
|
||||
|
||||
// 0x swap constants
|
||||
constexpr char kGoerliSwapBaseAPIURL[] = "https://goerli.api.0x.org/";
|
||||
|
||||
@@ -41,7 +41,22 @@ mojom::SwapResponsePtr ParseSwapResponse(const std::string& json,
|
||||
// "sources":[...],
|
||||
// "allowanceTarget":"0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
// "sellTokenToEthRate":"1900.44962824532464391",
|
||||
// "buyTokenToEthRate":"1"
|
||||
// "buyTokenToEthRate":"1",
|
||||
// "estimatedPriceImpact": "0.7232",
|
||||
// "sources": [
|
||||
// {
|
||||
// "name": "0x",
|
||||
// "proportion": "0",
|
||||
// },
|
||||
// {
|
||||
// "name": "Uniswap_V2",
|
||||
// "proportion": "1",
|
||||
// },
|
||||
// {
|
||||
// "name": "Curve",
|
||||
// "proportion": "0",
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
|
||||
absl::optional<base::Value> records_v =
|
||||
@@ -89,6 +104,14 @@ mojom::SwapResponsePtr ParseSwapResponse(const std::string& json,
|
||||
swap_response_value->sell_token_to_eth_rate;
|
||||
swap_response->buy_token_to_eth_rate =
|
||||
swap_response_value->buy_token_to_eth_rate;
|
||||
swap_response->estimated_price_impact =
|
||||
swap_response_value->estimated_price_impact;
|
||||
|
||||
for (const auto& source_value : swap_response_value->sources) {
|
||||
swap_response->sources.push_back(
|
||||
mojom::ZeroExSource::New(source_value.name, source_value.proportion));
|
||||
}
|
||||
|
||||
return swap_response;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,14 @@ TEST(SwapResponseParserUnitTest, ParsePriceQuote) {
|
||||
"sources":[],
|
||||
"allowanceTarget":"0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"sellTokenToEthRate":"1900.44962824532464391",
|
||||
"buyTokenToEthRate":"1"
|
||||
"buyTokenToEthRate":"1",
|
||||
"estimatedPriceImpact": "0.7232",
|
||||
"sources": [
|
||||
{
|
||||
"name": "Uniswap_V2",
|
||||
"proportion": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
)");
|
||||
mojom::SwapResponsePtr swap_response = ParseSwapResponse(json, false);
|
||||
@@ -110,6 +117,10 @@ TEST(SwapResponseParserUnitTest, ParsePriceQuote) {
|
||||
"0xdef1c0ded9bec7f1a1670819833240f027b25eff");
|
||||
ASSERT_EQ(swap_response->sell_token_to_eth_rate, "1900.44962824532464391");
|
||||
ASSERT_EQ(swap_response->buy_token_to_eth_rate, "1");
|
||||
ASSERT_EQ(swap_response->estimated_price_impact, "0.7232");
|
||||
ASSERT_EQ(swap_response->sources.size(), 1UL);
|
||||
ASSERT_EQ(swap_response->sources.at(0)->name, "Uniswap_V2");
|
||||
ASSERT_EQ(swap_response->sources.at(0)->proportion, "1");
|
||||
|
||||
json = R"({"price": "3"})";
|
||||
ASSERT_FALSE(ParseSwapResponse(json, false));
|
||||
@@ -143,7 +154,14 @@ TEST(SwapResponseParserUnitTest, ParseTransactionPayload) {
|
||||
"sources":[],
|
||||
"allowanceTarget":"0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"sellTokenToEthRate":"1900.44962824532464391",
|
||||
"buyTokenToEthRate":"1"
|
||||
"buyTokenToEthRate":"1",
|
||||
"estimatedPriceImpact": "0.7232",
|
||||
"sources": [
|
||||
{
|
||||
"name": "Uniswap_V2",
|
||||
"proportion": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
)");
|
||||
mojom::SwapResponsePtr swap_response = ParseSwapResponse(json, true);
|
||||
@@ -170,6 +188,10 @@ TEST(SwapResponseParserUnitTest, ParseTransactionPayload) {
|
||||
"0xdef1c0ded9bec7f1a1670819833240f027b25eff");
|
||||
ASSERT_EQ(swap_response->sell_token_to_eth_rate, "1900.44962824532464391");
|
||||
ASSERT_EQ(swap_response->buy_token_to_eth_rate, "1");
|
||||
ASSERT_EQ(swap_response->estimated_price_impact, "0.7232");
|
||||
ASSERT_EQ(swap_response->sources.size(), 1UL);
|
||||
ASSERT_EQ(swap_response->sources.at(0)->name, "Uniswap_V2");
|
||||
ASSERT_EQ(swap_response->sources.at(0)->proportion, "1");
|
||||
|
||||
json = R"({"price": "3"})";
|
||||
ASSERT_FALSE(ParseSwapResponse(json, true));
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
namespace swap_responses {
|
||||
dictionary ZeroExSource {
|
||||
DOMString name;
|
||||
DOMString proportion;
|
||||
};
|
||||
|
||||
dictionary SwapResponse0x {
|
||||
DOMString price;
|
||||
DOMString? guaranteedPrice;
|
||||
@@ -20,10 +25,11 @@ namespace swap_responses {
|
||||
DOMString sellTokenAddress;
|
||||
DOMString buyAmount;
|
||||
DOMString sellAmount;
|
||||
// TODO(bbondy): sources
|
||||
DOMString allowanceTarget;
|
||||
DOMString sellTokenToEthRate;
|
||||
DOMString buyTokenToEthRate;
|
||||
DOMString estimatedPriceImpact;
|
||||
ZeroExSource[] sources;
|
||||
};
|
||||
|
||||
dictionary JupiterMarketInfoFee {
|
||||
|
||||
@@ -250,7 +250,14 @@ TEST_F(SwapServiceUnitTest, GetPriceQuote) {
|
||||
"sources":[],
|
||||
"allowanceTarget":"0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"sellTokenToEthRate":"1900.44962824532464391",
|
||||
"buyTokenToEthRate":"1"
|
||||
"buyTokenToEthRate":"1",
|
||||
"estimatedPriceImpact": "0.7232",
|
||||
"sources": [
|
||||
{
|
||||
"name": "Uniswap_V2",
|
||||
"proportion": "1"
|
||||
}
|
||||
]
|
||||
})");
|
||||
|
||||
auto expected_swap_response = brave_wallet::mojom::SwapResponse::New();
|
||||
@@ -271,6 +278,12 @@ TEST_F(SwapServiceUnitTest, GetPriceQuote) {
|
||||
"0xdef1c0ded9bec7f1a1670819833240f027b25eff";
|
||||
expected_swap_response->sell_token_to_eth_rate = "1900.44962824532464391";
|
||||
expected_swap_response->buy_token_to_eth_rate = "1";
|
||||
expected_swap_response->estimated_price_impact = "0.7232";
|
||||
|
||||
auto source = brave_wallet::mojom::ZeroExSource::New();
|
||||
source->name = "Uniswap_V2";
|
||||
source->proportion = "1";
|
||||
expected_swap_response->sources.push_back(source.Clone());
|
||||
|
||||
bool callback_run = false;
|
||||
swap_service_->GetPriceQuote(
|
||||
@@ -325,7 +338,14 @@ TEST_F(SwapServiceUnitTest, GetTransactionPayload) {
|
||||
"sources":[],
|
||||
"allowanceTarget":"0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"sellTokenToEthRate":"1900.44962824532464391",
|
||||
"buyTokenToEthRate":"1"
|
||||
"buyTokenToEthRate":"1",
|
||||
"estimatedPriceImpact": "0.7232",
|
||||
"sources": [
|
||||
{
|
||||
"name": "Uniswap_V2",
|
||||
"proportion": "1"
|
||||
}
|
||||
]
|
||||
})");
|
||||
|
||||
auto expected_swap_response = brave_wallet::mojom::SwapResponse::New();
|
||||
@@ -349,6 +369,11 @@ TEST_F(SwapServiceUnitTest, GetTransactionPayload) {
|
||||
"0xdef1c0ded9bec7f1a1670819833240f027b25eff";
|
||||
expected_swap_response->sell_token_to_eth_rate = "1900.44962824532464391";
|
||||
expected_swap_response->buy_token_to_eth_rate = "1";
|
||||
expected_swap_response->estimated_price_impact = "0.7232";
|
||||
auto source = brave_wallet::mojom::ZeroExSource::New();
|
||||
source->name = "Uniswap_V2";
|
||||
source->proportion = "1";
|
||||
expected_swap_response->sources.push_back(source.Clone());
|
||||
|
||||
bool callback_run = false;
|
||||
swap_service_->GetTransactionPayload(
|
||||
|
||||
@@ -322,6 +322,11 @@ struct SwapParams {
|
||||
string gas_price;
|
||||
};
|
||||
|
||||
struct ZeroExSource {
|
||||
string name;
|
||||
string proportion;
|
||||
};
|
||||
|
||||
struct SwapResponse {
|
||||
string price;
|
||||
string guaranteed_price; // Unused for price quote response
|
||||
@@ -340,7 +345,8 @@ struct SwapResponse {
|
||||
string allowance_target;
|
||||
string sell_token_to_eth_rate;
|
||||
string buy_token_to_eth_rate;
|
||||
// Note we could also expose "sources" later
|
||||
string estimated_price_impact;
|
||||
array<ZeroExSource> sources;
|
||||
};
|
||||
|
||||
// Structs to model Jupiter (swap) HTTP API interactions
|
||||
|
||||
@@ -56,7 +56,9 @@ export class MockedWalletApiProxy {
|
||||
sellAmount: '124067000000000000',
|
||||
allowanceTarget: '0x0000000000000000000000000000000000000000',
|
||||
sellTokenToEthRate: '1',
|
||||
buyTokenToEthRate: '1720.180416'
|
||||
buyTokenToEthRate: '1720.180416',
|
||||
estimatedPriceImpact: '0.0782',
|
||||
sources: []
|
||||
}
|
||||
|
||||
mockTransaction = {
|
||||
@@ -76,7 +78,9 @@ export class MockedWalletApiProxy {
|
||||
buyAmount: '0',
|
||||
sellAmount: '0',
|
||||
sellTokenToEthRate: '1',
|
||||
buyTokenToEthRate: '1'
|
||||
buyTokenToEthRate: '1',
|
||||
estimatedPriceImpact: '0.0782',
|
||||
sources: []
|
||||
}
|
||||
|
||||
swapService: Partial<InstanceType<typeof BraveWallet.SwapServiceInterface>> = {
|
||||
|
||||
@@ -346,11 +346,20 @@ handler.on(WalletActions.selectPortfolioTimeline.type, async (store: Store, payl
|
||||
|
||||
handler.on(WalletActions.sendTransaction.type, async (
|
||||
store: Store,
|
||||
payload: SendEthTransactionParams | SendFilTransactionParams | SendSolTransactionParams
|
||||
payload:
|
||||
| Omit<SendEthTransactionParams, 'hasEIP1559Support'>
|
||||
| SendFilTransactionParams
|
||||
| SendSolTransactionParams
|
||||
) => {
|
||||
const { wallet: walletState } = store.getState()
|
||||
|
||||
let addResult
|
||||
if (payload.coin === BraveWallet.CoinType.ETH) {
|
||||
addResult = await sendEthTransaction(store, payload as SendEthTransactionParams)
|
||||
addResult = await sendEthTransaction({
|
||||
...payload,
|
||||
hasEIP1559Support: !!walletState.selectedNetwork && !!walletState.selectedAccount &&
|
||||
hasEIP1559Support(walletState.selectedAccount, walletState.selectedNetwork)
|
||||
})
|
||||
} else if (payload.coin === BraveWallet.CoinType.FIL) {
|
||||
addResult = await sendFilTransaction(payload as SendFilTransactionParams)
|
||||
} else if (payload.coin === BraveWallet.CoinType.SOL) {
|
||||
|
||||
@@ -34,7 +34,7 @@ import { loadTimeData } from '../../../common/loadTimeData'
|
||||
import { walletApi } from '../slices/api.slice'
|
||||
|
||||
import getAPIProxy from './bridge'
|
||||
import { Dispatch, State, Store } from './types'
|
||||
import { Dispatch, State } from './types'
|
||||
import { getHardwareKeyring } from '../api/hardware_keyrings'
|
||||
import { GetAccountsHardwareOperationResult, SolDerivationPaths } from '../hardware/types'
|
||||
import EthereumLedgerBridgeKeyring from '../hardware/ledgerjs/eth_ledger_bridge_keyring'
|
||||
@@ -61,7 +61,7 @@ export const getERC20Allowance = (
|
||||
if (result.error === BraveWallet.ProviderError.kSuccess) {
|
||||
resolve(result.allowance)
|
||||
} else {
|
||||
reject()
|
||||
reject(result.errorMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -107,25 +107,50 @@ export const onConnectHardwareWallet = (opts: HardwareWalletConnectOpts): Promis
|
||||
})
|
||||
}
|
||||
|
||||
export const getBalance = (address: string, coin: BraveWallet.CoinType): Promise<string> => {
|
||||
export const getBalance = async (address: string, coin: BraveWallet.CoinType): Promise<string> => {
|
||||
const { jsonRpcService } = getAPIProxy()
|
||||
const chainId = await jsonRpcService.getChainId(coin)
|
||||
return await getBalanceForChainId(address, coin, chainId.chainId)
|
||||
}
|
||||
|
||||
export function getBalanceForChainId (address: string, coin: BraveWallet.CoinType, chainId: string): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { jsonRpcService } = getAPIProxy()
|
||||
const chainId = await jsonRpcService.getChainId(coin)
|
||||
|
||||
if (coin === BraveWallet.CoinType.SOL) {
|
||||
const result = await jsonRpcService.getSolanaBalance(address, chainId.chainId)
|
||||
const result = await jsonRpcService.getSolanaBalance(address, chainId)
|
||||
if (result.error === BraveWallet.SolanaProviderError.kSuccess) {
|
||||
resolve(Amount.normalize(result.balance.toString()))
|
||||
} else {
|
||||
reject()
|
||||
reject(result.errorMessage)
|
||||
}
|
||||
return
|
||||
}
|
||||
const result = await jsonRpcService.getBalance(address, coin, chainId.chainId)
|
||||
const result = await jsonRpcService.getBalance(address, coin, chainId)
|
||||
if (result.error === BraveWallet.ProviderError.kSuccess) {
|
||||
resolve(Amount.normalize(result.balance))
|
||||
} else {
|
||||
reject()
|
||||
reject(result.errorMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getTokenBalanceForChainId (contract: string, address: string, coin: BraveWallet.CoinType, chainId: string): Promise<string> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const { jsonRpcService } = getAPIProxy()
|
||||
if (coin === BraveWallet.CoinType.SOL) {
|
||||
const result = await jsonRpcService.getSPLTokenAccountBalance(address, contract, chainId)
|
||||
if (result.error === BraveWallet.SolanaProviderError.kSuccess) {
|
||||
resolve(Amount.normalize(result.amount))
|
||||
} else {
|
||||
reject(result.errorMessage)
|
||||
}
|
||||
return
|
||||
}
|
||||
const result = await jsonRpcService.getERC20TokenBalance(contract, address, chainId)
|
||||
if (result.error === BraveWallet.ProviderError.kSuccess) {
|
||||
resolve(Amount.normalize(result.balance))
|
||||
} else {
|
||||
reject(result.errorMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -883,7 +908,7 @@ export function hasEIP1559Support (account: WalletAccountType, network: BraveWal
|
||||
return keyringSupportsEIP1559 && network.isEip1559
|
||||
}
|
||||
|
||||
export async function sendEthTransaction (store: Store, payload: SendEthTransactionParams) {
|
||||
export async function sendEthTransaction (payload: SendEthTransactionParams) {
|
||||
const apiProxy = getAPIProxy()
|
||||
/***
|
||||
* Determine whether to create a legacy or EIP-1559 transaction.
|
||||
@@ -910,10 +935,7 @@ export async function sendEthTransaction (store: Store, payload: SendEthTransact
|
||||
|
||||
// Check if network and keyring support EIP-1559.
|
||||
default:
|
||||
const { selectedAccount, selectedNetwork } = store.getState().wallet
|
||||
isEIP1559 = selectedNetwork && selectedAccount
|
||||
? hasEIP1559Support(selectedAccount, selectedNetwork)
|
||||
: false
|
||||
isEIP1559 = payload.hasEIP1559Support
|
||||
}
|
||||
|
||||
const { chainId } = await apiProxy.jsonRpcService.getChainId(BraveWallet.CoinType.ETH)
|
||||
@@ -989,7 +1011,7 @@ export async function sendSolanaSerializedTransaction (payload: SolanaSerialized
|
||||
)
|
||||
if (result.error !== BraveWallet.ProviderError.kSuccess) {
|
||||
console.error(`Failed to sign Solana message: ${result.errorMessage}`)
|
||||
return { success: false, errorMessage: result.errorMessage }
|
||||
return { success: false, errorMessage: result.errorMessage, txMetaId: '' }
|
||||
} else {
|
||||
return await txService.addUnapprovedTransaction(
|
||||
// @ts-expect-error google closure is ok with undefined for other fields but mojom runtime is not
|
||||
@@ -1000,3 +1022,13 @@ export async function sendSolanaSerializedTransaction (payload: SolanaSerialized
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function getSwapService () {
|
||||
const { swapService } = getAPIProxy()
|
||||
return swapService
|
||||
}
|
||||
|
||||
export function getEthTxManagerProxy () {
|
||||
const { ethTxManagerProxy } = getAPIProxy()
|
||||
return ethTxManagerProxy
|
||||
}
|
||||
|
||||
@@ -437,7 +437,8 @@ export default function useSend (isSendTab?: boolean) {
|
||||
.multiplyByDecimals(selectedSendAsset.decimals) // ETH → Wei conversion
|
||||
.value // extract BigNumber object wrapped by Amount
|
||||
|
||||
return amountBN && amountBN.decimalPlaces() > 0
|
||||
const amountDP = amountBN && amountBN.decimalPlaces()
|
||||
return amountDP && amountDP > 0
|
||||
? 'fromAmountDecimalsOverflow'
|
||||
: undefined
|
||||
}, [sendAmount, selectedSendAsset])
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
ExpirationPresetObjectType,
|
||||
JupiterErrorResponse,
|
||||
OrderTypes,
|
||||
SendTransactionParams,
|
||||
SendEthTransactionParams,
|
||||
SlippagePresetObjectType,
|
||||
SwapErrorResponse,
|
||||
SwapValidationErrorType,
|
||||
@@ -78,7 +78,8 @@ const hasDecimalsOverflow = (amount: string, asset?: BraveWallet.BlockchainToken
|
||||
}
|
||||
|
||||
const amountBaseWrapped = new Amount(amount).multiplyByDecimals(asset.decimals)
|
||||
return amountBaseWrapped.value && amountBaseWrapped.value.decimalPlaces() > 0
|
||||
const amountBaseWrappedDP = amountBaseWrapped.value && amountBaseWrapped.value.decimalPlaces()
|
||||
return amountBaseWrappedDP && amountBaseWrappedDP > 0
|
||||
}
|
||||
|
||||
export enum SwapProvider {
|
||||
@@ -442,7 +443,7 @@ export default function useSwap ({ fromAsset: fromAssetProp, toAsset: toAssetPro
|
||||
maxFeePerGas = gasEstimates?.fastMaxFeePerGas
|
||||
}
|
||||
|
||||
const params: SendTransactionParams = {
|
||||
const params: SendEthTransactionParams = {
|
||||
from: accountAddress,
|
||||
to,
|
||||
value: new Amount(value).toHex(),
|
||||
@@ -450,7 +451,8 @@ export default function useSwap ({ fromAsset: fromAssetProp, toAsset: toAssetPro
|
||||
data: hexStrToNumberArray(data),
|
||||
maxPriorityFeePerGas,
|
||||
maxFeePerGas,
|
||||
coin: BraveWallet.CoinType.ETH
|
||||
coin: BraveWallet.CoinType.ETH,
|
||||
hasEIP1559Support: isEIP1559
|
||||
}
|
||||
|
||||
dispatch(WalletActions.sendTransaction(params))
|
||||
|
||||
@@ -464,6 +464,7 @@ export interface SolanaSerializedTransactionParams {
|
||||
|
||||
export interface SendEthTransactionParams extends BaseEthTransactionParams {
|
||||
data?: number[]
|
||||
hasEIP1559Support: boolean
|
||||
}
|
||||
|
||||
export type SendTransactionParams = SendEthTransactionParams | SendFilTransactionParams | SendSolTransactionParams
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
// Copyright (c) 2022 The Brave Authors. All rights reserved.
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
import {
|
||||
ApproveERC20Params,
|
||||
BlockchainToken,
|
||||
ETHSendTransactionParams,
|
||||
JupiterQuoteParams,
|
||||
JupiterSwapParams,
|
||||
NetworkInfo,
|
||||
SOLSendTransactionParams,
|
||||
WalletAccount,
|
||||
ZeroExQuoteResponse,
|
||||
ZeroExSwapParams,
|
||||
ZeroExSwapResponse,
|
||||
SwapFee
|
||||
} from '@brave/swap-interface'
|
||||
import {
|
||||
BraveWallet,
|
||||
SendEthTransactionParams,
|
||||
SolanaSerializedTransactionParams,
|
||||
WalletAccountType
|
||||
} from '../../../constants/types'
|
||||
import getAPIProxy from '../../../common/async/bridge'
|
||||
import { getNetworkLogo } from '../../../options/asset-options'
|
||||
|
||||
function getTokenParam (token: BlockchainToken): string {
|
||||
if (token.coingeckoId) {
|
||||
return token.coingeckoId
|
||||
}
|
||||
|
||||
const isEthereumNetwork = token.chainId === BraveWallet.MAINNET_CHAIN_ID
|
||||
|
||||
if (!isEthereumNetwork) {
|
||||
return token.symbol.toLowerCase()
|
||||
}
|
||||
|
||||
if (token.contractAddress === '') {
|
||||
return token.symbol.toLowerCase()
|
||||
}
|
||||
|
||||
return token.contractAddress
|
||||
}
|
||||
|
||||
export function makeGetTokenPrice (toAssetSymbol: string) {
|
||||
async function getTokenPrice (token: BlockchainToken) {
|
||||
const { assetRatioService } = getAPIProxy()
|
||||
|
||||
const param = getTokenParam(token)
|
||||
const { success, values } = await assetRatioService.getPrice(
|
||||
[param],
|
||||
[toAssetSymbol.toLowerCase()],
|
||||
BraveWallet.AssetPriceTimeframe.OneDay
|
||||
)
|
||||
|
||||
if (success) {
|
||||
return values[0].price
|
||||
}
|
||||
|
||||
throw new Error(`Failed to fetch price: ${param}`)
|
||||
}
|
||||
|
||||
return getTokenPrice
|
||||
}
|
||||
|
||||
export function makeNetworkInfo (network: BraveWallet.NetworkInfo): NetworkInfo {
|
||||
return {
|
||||
chainId: network.chainId,
|
||||
chainName: network.chainName,
|
||||
blockExplorerUrl: network.blockExplorerUrls[0],
|
||||
logo: getNetworkLogo(network),
|
||||
symbol: network.symbol,
|
||||
symbolName: network.symbolName,
|
||||
decimals: network.decimals,
|
||||
coin: network.coin,
|
||||
isEIP1559: network.isEip1559
|
||||
}
|
||||
}
|
||||
|
||||
export function makeWalletAccount (account: WalletAccountType): WalletAccount {
|
||||
return {
|
||||
id: account.address,
|
||||
name: account.name,
|
||||
address: account.address,
|
||||
coin: account.coin
|
||||
}
|
||||
}
|
||||
|
||||
export function makeBlockchainToken (token: BraveWallet.BlockchainToken): BlockchainToken {
|
||||
return {
|
||||
contractAddress: token.contractAddress,
|
||||
name: token.name,
|
||||
logo: token.logo,
|
||||
isToken: token.coin === BraveWallet.CoinType.ETH ? token.isErc20 : token.contractAddress !== '',
|
||||
visible: token.visible,
|
||||
decimals: token.decimals,
|
||||
symbol: token.symbol,
|
||||
coingeckoId: token.coingeckoId,
|
||||
chainId: token.chainId,
|
||||
coin: token.coin
|
||||
}
|
||||
}
|
||||
|
||||
export function makeSwapService () {
|
||||
async function getZeroExPriceQuote (params: ZeroExSwapParams) {
|
||||
const { swapService } = getAPIProxy()
|
||||
const { success, errorResponse, response } = await swapService.getPriceQuote(params)
|
||||
|
||||
if (success) {
|
||||
return {
|
||||
price: response?.price || '',
|
||||
value: response?.value || '',
|
||||
gas: response?.gas || '',
|
||||
estimatedGas: response?.estimatedGas || '',
|
||||
gasPrice: response?.gasPrice || '',
|
||||
protocolFee: response?.protocolFee || '',
|
||||
minimumProtocolFee: response?.minimumProtocolFee || '',
|
||||
buyTokenAddress: response?.buyTokenAddress || '',
|
||||
sellTokenAddress: response?.sellTokenAddress || '',
|
||||
buyAmount: response?.buyAmount || '',
|
||||
sellAmount: response?.sellAmount || '',
|
||||
allowanceTarget: response?.allowanceTarget || '',
|
||||
sellTokenToEthRate: response?.sellTokenToEthRate || '',
|
||||
buyTokenToEthRate: response?.buyTokenToEthRate || '',
|
||||
estimatedPriceImpact: response?.estimatedPriceImpact || '',
|
||||
sources: response?.sources || []
|
||||
} as ZeroExQuoteResponse
|
||||
}
|
||||
|
||||
throw new Error(errorResponse || '')
|
||||
}
|
||||
|
||||
async function getZeroExTransactionPayload (params: ZeroExSwapParams) {
|
||||
const { swapService } = getAPIProxy()
|
||||
const { success, errorResponse, response } = await swapService.getTransactionPayload(params)
|
||||
if (success) {
|
||||
return {
|
||||
price: response?.price || '',
|
||||
value: response?.value || '',
|
||||
gas: response?.gas || '',
|
||||
estimatedGas: response?.estimatedGas || '',
|
||||
gasPrice: response?.gasPrice || '',
|
||||
protocolFee: response?.protocolFee || '',
|
||||
minimumProtocolFee: response?.minimumProtocolFee || '',
|
||||
buyTokenAddress: response?.buyTokenAddress || '',
|
||||
sellTokenAddress: response?.sellTokenAddress || '',
|
||||
buyAmount: response?.buyAmount || '',
|
||||
sellAmount: response?.sellAmount || '',
|
||||
allowanceTarget: response?.allowanceTarget || '',
|
||||
sellTokenToEthRate: response?.sellTokenToEthRate || '',
|
||||
buyTokenToEthRate: response?.buyTokenToEthRate || '',
|
||||
estimatedPriceImpact: response?.estimatedPriceImpact || '',
|
||||
sources: response?.sources || [],
|
||||
guaranteedPrice: response?.guaranteedPrice || '',
|
||||
to: response?.to || '',
|
||||
data: response?.data || ''
|
||||
} as ZeroExSwapResponse
|
||||
}
|
||||
|
||||
throw new Error(errorResponse || '')
|
||||
}
|
||||
|
||||
async function getJupiterQuote (params: JupiterQuoteParams) {
|
||||
const { swapService } = getAPIProxy()
|
||||
const { success, errorResponse, response } = await swapService.getJupiterQuote(params)
|
||||
if (success) {
|
||||
return {
|
||||
routes: response?.routes || []
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(errorResponse || '')
|
||||
}
|
||||
|
||||
async function getJupiterTransactionsPayload (params: JupiterSwapParams) {
|
||||
const { swapService } = getAPIProxy()
|
||||
const { success, errorResponse, response } = await swapService.getJupiterSwapTransactions(
|
||||
params
|
||||
)
|
||||
if (success) {
|
||||
return {
|
||||
setupTransaction: response?.setupTransaction || '',
|
||||
swapTransaction: response?.swapTransaction || '',
|
||||
cleanupTransaction: response?.cleanupTransaction || ''
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(errorResponse || '')
|
||||
}
|
||||
|
||||
async function isSwapSupported (chainId: string) {
|
||||
const { swapService } = getAPIProxy()
|
||||
return (await swapService.isSwapSupported(chainId)).result
|
||||
}
|
||||
|
||||
async function getBraveFeeForAsset (asset: BlockchainToken) {
|
||||
if (asset.coin === BraveWallet.CoinType.ETH) {
|
||||
return {
|
||||
fee: '0.875',
|
||||
discount: '0'
|
||||
} as SwapFee
|
||||
}
|
||||
|
||||
const { swapService } = getAPIProxy()
|
||||
const hasFee = (await swapService.hasJupiterFeesForTokenMint(asset.contractAddress)).result
|
||||
|
||||
return {
|
||||
fee: '0.85',
|
||||
discount: hasFee ? '0' : '100'
|
||||
} as SwapFee
|
||||
}
|
||||
|
||||
return {
|
||||
getZeroExPriceQuote,
|
||||
getZeroExTransactionPayload,
|
||||
getJupiterQuote,
|
||||
getJupiterTransactionsPayload,
|
||||
isSwapSupported,
|
||||
getBraveFeeForAsset
|
||||
}
|
||||
}
|
||||
|
||||
export function makeGetGasPrice () {
|
||||
async function getGasPrice () {
|
||||
// FIXME: return the result of eth_gasPrice RPC
|
||||
return ''
|
||||
}
|
||||
|
||||
return getGasPrice
|
||||
}
|
||||
|
||||
export function makeGetGasPrice1559 () {
|
||||
async function getGasPrice1559 () {
|
||||
const { ethTxManagerProxy } = getAPIProxy()
|
||||
const result = await ethTxManagerProxy.getGasEstimation1559()
|
||||
if (result && result.estimation) {
|
||||
return result.estimation
|
||||
} else {
|
||||
throw Error('Failed to fetch EIP-1559 gas-pricing estimates')
|
||||
}
|
||||
}
|
||||
|
||||
return getGasPrice1559
|
||||
}
|
||||
|
||||
export function makeGetERC20ApproveData () {
|
||||
// FIXME - Remove contractAddress from ApproveERC20Params
|
||||
async function getERC20ApproveData (params: ApproveERC20Params) {
|
||||
const { ethTxManagerProxy } = getAPIProxy()
|
||||
const { success, data } = await ethTxManagerProxy.makeERC20ApproveData(
|
||||
params.spenderAddress,
|
||||
params.allowance
|
||||
)
|
||||
if (success) {
|
||||
return data
|
||||
} else {
|
||||
throw Error('Failed to make ERC20 approve data')
|
||||
}
|
||||
}
|
||||
|
||||
return getERC20ApproveData
|
||||
}
|
||||
|
||||
export function makeETHSendTransaction (
|
||||
func: (
|
||||
payload: SendEthTransactionParams
|
||||
) => Promise<{ success: boolean, txMetaId: string, errorMessage: string }>,
|
||||
hasEIP1559Support: boolean
|
||||
) {
|
||||
async function sendTransaction (params: ETHSendTransactionParams) {
|
||||
const { errorMessage } = await func({
|
||||
...params,
|
||||
hasEIP1559Support,
|
||||
coin: BraveWallet.CoinType.ETH
|
||||
})
|
||||
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return sendTransaction
|
||||
}
|
||||
|
||||
export function makeSOLSendTransaction (
|
||||
func: (
|
||||
params: SolanaSerializedTransactionParams
|
||||
) => Promise<{ success: boolean, txMetaId: string, errorMessage: string }>
|
||||
) {
|
||||
async function sendTransaction (params: SOLSendTransactionParams) {
|
||||
const { errorMessage } = await func({
|
||||
encodedTransaction: params.encodedTransaction,
|
||||
from: params.from,
|
||||
txType: BraveWallet.TransactionType.SolanaSwap,
|
||||
sendOptions: {
|
||||
maxRetries:
|
||||
params.sendOptions?.maxRetries !== undefined
|
||||
? ({
|
||||
maxRetries: params.sendOptions.maxRetries
|
||||
} as unknown as BraveWallet.OptionalMaxRetries)
|
||||
: undefined,
|
||||
preflightCommitment: params.sendOptions?.preflightCommitment,
|
||||
skipPreflight:
|
||||
params.sendOptions?.skipPreflight !== undefined
|
||||
? { skipPreflight: params.sendOptions.skipPreflight }
|
||||
: undefined
|
||||
}
|
||||
|
||||
// TODO: support groupId
|
||||
})
|
||||
|
||||
if (errorMessage) {
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return sendTransaction
|
||||
}
|
||||
|
||||
export function makeSwitchAccount () {
|
||||
async function switchAccount (account: WalletAccount) {
|
||||
const { keyringService } = getAPIProxy()
|
||||
await keyringService.setSelectedAccount(account.address, account.coin)
|
||||
}
|
||||
|
||||
return switchAccount
|
||||
}
|
||||
|
||||
export function makeSwitchNetwork () {
|
||||
async function switchNetwork (network: NetworkInfo) {
|
||||
const { jsonRpcService } = getAPIProxy()
|
||||
await jsonRpcService.setNetwork(network.chainId, network.coin)
|
||||
}
|
||||
|
||||
return switchNetwork
|
||||
}
|
||||
@@ -4,12 +4,149 @@
|
||||
// you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
import * as React from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import { NetworkInfo, Swap as SwapInterface } from '@brave/swap-interface'
|
||||
import '@brave/swap-interface/dist/style.css'
|
||||
|
||||
import { getLocale } from '$web-common/locale'
|
||||
import { WalletSelectors } from '../../../common/selectors'
|
||||
import {
|
||||
useSafeWalletSelector,
|
||||
useUnsafeWalletSelector
|
||||
} from '../../../common/hooks/use-safe-selector'
|
||||
import { useLib } from '../../../common/hooks'
|
||||
import { BraveWallet, WalletAccountType, WalletRoutes } from '../../../constants/types'
|
||||
|
||||
import {
|
||||
makeBlockchainToken,
|
||||
makeNetworkInfo,
|
||||
makeWalletAccount,
|
||||
makeSwapService,
|
||||
makeSOLSendTransaction,
|
||||
makeGetGasPrice,
|
||||
makeGetGasPrice1559,
|
||||
makeGetERC20ApproveData,
|
||||
makeETHSendTransaction,
|
||||
makeSwitchNetwork,
|
||||
makeSwitchAccount,
|
||||
makeGetTokenPrice
|
||||
} from './adapters'
|
||||
|
||||
export const Swap = () => {
|
||||
// render
|
||||
const selectedNetwork = useUnsafeWalletSelector(WalletSelectors.selectedNetwork)
|
||||
const selectedAccount = useUnsafeWalletSelector(
|
||||
WalletSelectors.selectedAccount
|
||||
)
|
||||
const accounts: WalletAccountType[] = useUnsafeWalletSelector(WalletSelectors.accounts)
|
||||
const networks: BraveWallet.NetworkInfo[] = useUnsafeWalletSelector(WalletSelectors.networkList)
|
||||
const defaultFiatCurrency = useSafeWalletSelector(WalletSelectors.defaultFiatCurrency)
|
||||
const fullTokenList: BraveWallet.BlockchainToken[] = useUnsafeWalletSelector(
|
||||
WalletSelectors.fullTokenList
|
||||
)
|
||||
const userVisibleTokensInfo: BraveWallet.BlockchainToken[] = useUnsafeWalletSelector(
|
||||
WalletSelectors.userVisibleTokensInfo
|
||||
)
|
||||
|
||||
const [supportedNetworks, setSupportedNetworks] = React.useState<NetworkInfo[]>([])
|
||||
|
||||
const tokensList = React.useMemo(() => {
|
||||
return [
|
||||
...userVisibleTokensInfo.filter(asset => asset.isErc20),
|
||||
...fullTokenList.filter(
|
||||
asset =>
|
||||
!userVisibleTokensInfo.some(
|
||||
token => token.contractAddress.toLowerCase() === asset.contractAddress.toLowerCase()
|
||||
)
|
||||
)
|
||||
]
|
||||
.filter(asset => !asset.isErc721)
|
||||
.map(asset => makeBlockchainToken(asset))
|
||||
}, [fullTokenList, userVisibleTokensInfo])
|
||||
|
||||
const {
|
||||
getBalanceForChainId,
|
||||
getTokenBalanceForChainId,
|
||||
sendSolanaSerializedTransaction,
|
||||
getSwapService,
|
||||
getERC20Allowance,
|
||||
sendEthTransaction,
|
||||
hasEIP1559Support
|
||||
} = useLib()
|
||||
|
||||
const swapServiceMojo = getSwapService()
|
||||
|
||||
React.useEffect(() => {
|
||||
;(async () => {
|
||||
const results = await Promise.all(
|
||||
networks.map(async e => (await swapServiceMojo.isSwapSupported(e.chainId)).result)
|
||||
)
|
||||
|
||||
const result = networks.filter((_, index) => results[index]).map(e => makeNetworkInfo(e))
|
||||
setSupportedNetworks(result)
|
||||
})()
|
||||
}, [networks])
|
||||
|
||||
// Memos
|
||||
const walletAccounts = React.useMemo(() => {
|
||||
return accounts.map(account => makeWalletAccount(account))
|
||||
}, [accounts])
|
||||
|
||||
const ethWalletAdapter = React.useMemo(() => {
|
||||
return {
|
||||
getGasPrice: makeGetGasPrice(),
|
||||
getGasPrice1559: makeGetGasPrice1559(),
|
||||
getERC20Allowance,
|
||||
getERC20ApproveData: makeGetERC20ApproveData(),
|
||||
sendTransaction: makeETHSendTransaction(
|
||||
sendEthTransaction,
|
||||
!!selectedNetwork && !!selectedAccount && hasEIP1559Support(selectedAccount, selectedNetwork)
|
||||
)
|
||||
}
|
||||
}, [selectedAccount, selectedNetwork])
|
||||
|
||||
const solWalletAdapter = React.useMemo(() => {
|
||||
return {
|
||||
sendTransaction: makeSOLSendTransaction(sendSolanaSerializedTransaction)
|
||||
}
|
||||
}, [])
|
||||
|
||||
let history = useHistory()
|
||||
const goBack = React.useCallback(() => {
|
||||
history.push(WalletRoutes.Portfolio)
|
||||
}, [history])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span>Brave Swap</span>
|
||||
{selectedNetwork && selectedAccount && (
|
||||
<SwapInterface
|
||||
getLocale={getLocale}
|
||||
network={makeNetworkInfo(selectedNetwork)}
|
||||
account={makeWalletAccount(selectedAccount)}
|
||||
walletAccounts={walletAccounts}
|
||||
switchAccount={makeSwitchAccount()}
|
||||
switchNetwork={makeSwitchNetwork()}
|
||||
getBalance={getBalanceForChainId}
|
||||
getTokenBalance={getTokenBalanceForChainId}
|
||||
// // FIXME - remove isSwapSupported()
|
||||
swapService={makeSwapService()}
|
||||
// // FIXME - implement mojo method to query available 0x exchanges
|
||||
// // This feature may be disabled until then.
|
||||
exchanges={[]}
|
||||
// // FIXME - remove getNetworkFeeEstimate, since chain-specific methods are
|
||||
// // already available in the wallet adapters. This is a stub to make tsc happy.
|
||||
getNetworkFeeEstimate={async () => ({ gasFee: '' })}
|
||||
assetsList={tokensList}
|
||||
solWalletAdapter={solWalletAdapter}
|
||||
ethWalletAdapter={ethWalletAdapter}
|
||||
getTokenPrice={makeGetTokenPrice(defaultFiatCurrency)}
|
||||
supportedNetworks={supportedNetworks}
|
||||
defaultBaseCurrency={defaultFiatCurrency}
|
||||
routeBackToWallet={goBack}
|
||||
isWalletConnected={true}
|
||||
isReady={!!selectedNetwork}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,10 +243,16 @@ export default class Amount {
|
||||
let decimals
|
||||
let value
|
||||
|
||||
if (this.value === undefined || this.value.isNaN()) {
|
||||
const valueDP = this.value && this.value.decimalPlaces()
|
||||
if (
|
||||
this.value === undefined ||
|
||||
this.value.isNaN() ||
|
||||
valueDP === null ||
|
||||
valueDP === undefined
|
||||
) {
|
||||
return ''
|
||||
} else if (
|
||||
this.value.decimalPlaces() < 2 || this.value.isGreaterThanOrEqualTo(10)
|
||||
valueDP < 2 || this.value.isGreaterThanOrEqualTo(10)
|
||||
) {
|
||||
decimals = 2
|
||||
value = this.value.toNumber()
|
||||
|
||||
@@ -735,4 +735,62 @@
|
||||
<message name="IDS_BRAVE_WALLET_NFT_FETCHING_ERROR" desc="Error message displayed when nft metadata is not successfully fetched">Something went wrong when fetching NFT details. Please try again later.</message>
|
||||
<message name="IDS_BRAVE_WALLET_ENTER_A_PASSSWORD_TO_CONTINUE" desc="Prompt to enter a password before continuing">Enter a password to continue</message>
|
||||
<message name="IDS_BRAVE_WALLET_ENTER_YOUR_PASSWORD_TO_START_BACKUP" desc="Password prompt description for backing up wallet">Enter your Brave Wallet password to start backing up wallet.</message>
|
||||
<message name="IDS_BRAVE_SWAP" desc="Swap main title">Swap</message>
|
||||
<message name="IDS_BRAVE_SWAP_REVIEW_ORDER" desc="Text for swap button">Review order</message>
|
||||
<message name="IDS_BRAVE_SWAP_APPROVE_TOKEN" desc="Text for swap button while approving ERC20 token">Approve <ph name="TOKEN">$1</ph></message>
|
||||
<message name="IDS_BRAVE_SWAP_INSUFFICIENT_BALANCE" desc="Text for swap button when token token balance is insufficient">Insufficient <ph name="TOKEN">$1</ph> balance</message>
|
||||
<message name="IDS_BRAVE_SWAP_SELECT_TOKEN" desc="Dropdown text to select token">Select token</message>
|
||||
<message name="IDS_BRAVE_SWAP_HALF" desc="Amount preset button text for half">Half</message>
|
||||
<message name="IDS_BRAVE_SWAP_MAX" desc="Amount preset button text for max">Max</message>
|
||||
<message name="IDS_BRAVE_SWAP_ENTER_AN_AMOUNT" desc="Text prompting to enter an amount">Enter an amount</message>
|
||||
<message name="IDS_BRAVE_SWAP_FINDING_PRICE" desc="Loader text while quotes are fetched">Finding the best price for you</message>
|
||||
<message name="IDS_BRAVE_SWAP_BALANCE" desc="Text indicating account balance">Balance:</message>
|
||||
<message name="IDS_BRAVE_SWAP_SELECT_A_TOKEN" desc="Text prompting to select a token to swap">Select a token to swap</message>
|
||||
<message name="IDS_BRAVE_SWAP_SHOW_TOKENS_WITH_ZERO_BALANCES" desc="Button text to show tokens with zero balance">Show tokens with no balance</message>
|
||||
<message name="IDS_BRAVE_SWAP_HIDE_TOKENS_WITH_ZERO_BALANCES" desc="Button text to hide tokens with zero balance">Hide zero balance</message>
|
||||
<message name="IDS_BRAVE_SWAP_SEARCH_TOKEN" desc="Text prompt to search token by name">Search token by name</message>
|
||||
<message name="IDS_BRAVE_SWAP_OPTION" desc="Swap quote option">Option</message>
|
||||
<message name="IDS_BRAVE_SWAP_RATE" desc="Swap exchange rate">Rate</message>
|
||||
<message name="IDS_BRAVE_SWAP_PRICE_IMPACT" desc="Swap price impact">Price impact</message>
|
||||
<message name="IDS_BRAVE_SWAP_MINIMUM_RECEIVED_AFTER_SLIPPAGE" desc="Minimum guaranteed amount user will get after the swap">Minimum received after slippage</message>
|
||||
<message name="IDS_BRAVE_SWAP_NETWORK_FEE" desc="Text indicating network fees">Network fee</message>
|
||||
<message name="IDS_BRAVE_SWAP_BRAVE_FEE" desc="Text indicating Brave fee for swaps">Brave fee</message>
|
||||
<message name="IDS_BRAVE_SWAP_FREE" desc="Text indicating free Brave fees for swaps">Free</message>
|
||||
<message name="IDS_BRAVE_SWAP_LIQUIDITY_PROVIDER" desc="Liquidity provider for the swap quote">Liquidity provider</message>
|
||||
<message name="IDS_BRAVE_SWAP_SWAP_AND_SEND" desc="Swap and send to a specific address in one transaction">Swap & send</message>
|
||||
<message name="IDS_BRAVE_SWAP_NO_EXTRA_FEES" desc="Text indicating swap and send has no extra fees">NO extra fees!</message>
|
||||
<message name="IDS_BRAVE_SWAP_CONFIRM_ADDRESS" desc="Text to confirm that the address is correct">I confirm that the address above is correct</message>
|
||||
<message name="IDS_BRAVE_SWAP_ADDRESS_INPUT_PLACEHOLDER" desc="Text to prompt user to enter address for swap and send">Enter recipient's Ethereum address</message>
|
||||
<message name="IDS_BRAVE_SWAP_SELECT_ACCOUNT" desc="Button text to select an account">Select an account</message>
|
||||
<message name="IDS_BRAVE_SWAP_TO_ACCOUNT" desc="Text option indicating that Swap and Send must use one of user's accounts">To my account</message>
|
||||
<message name="IDS_BRAVE_SWAP_TO_ADDRESS" desc="Text option indicating that Swap and Send must use a specific address">To another address</message>
|
||||
<message name="IDS_BRAVE_SWAP_SLOW" desc="Gas price corresponding to slow speed for confirmation">Slow</message>
|
||||
<message name="IDS_BRAVE_SWAP_AVERAGE" desc="Gas price corresponding to average speed for confirmation">Average</message>
|
||||
<message name="IDS_BRAVE_SWAP_FAST" desc="Gas price corresponding to fast speed for confirmation">Fast</message>
|
||||
<message name="IDS_BRAVE_SWAP_GWEI" desc="Unit to use for gas price (giga-wei)">Gwei</message>
|
||||
<message name="IDS_BRAVE_SWAP_SETTINGS" desc="Swap settings">Swap settings</message>
|
||||
<message name="IDS_BRAVE_SWAP_SLIPPAGE_TOLERANCE" desc="Percentage tolerance to allow for slippage during the swap">Slippage tolerance</message>
|
||||
<message name="IDS_BRAVE_SWAP_EXCHANGES" desc="Exchanges to use for the swap trade">Exchanges</message>
|
||||
<message name="IDS_BRAVE_SWAP_DIRECT_ROUTE_TITLE" desc="Text indicating that swap must use direct routes in the trade">Direct route only</message>
|
||||
<message name="IDS_BRAVE_SWAP_DIRECT_ROUTE_DESCRIPTION" desc="Text description direct swap routes option">It insures only direct routing and also disables split trade trading</message>
|
||||
<message name="IDS_BRAVE_SWAP_NETWORK_FEE_DESCRIPTION" desc="Network fee description">Brave uses the top 60 tokens for intermediate routing for performance optimization</message>
|
||||
<message name="IDS_BRAVE_SWAP_COINGECKO_CHEAPER" desc="Quote rate is cheaper than CoinGecko"><ph name="VALUE">$1<ex>0.12</ex></ph>% cheaper than CoinGecko</message>
|
||||
<message name="IDS_BRAVE_SWAP_COINGECKO_WITHIN" desc="Quote rate is within small percentage of CoinGecko">Within <ph name="VALUE">$1<ex>0.12</ex></ph>% CoinGecko</message>
|
||||
<message name="IDS_BRAVE_SWAP_COINGECKO_EXPENSIVE" desc="Quote rate is more expensive than CoinGecko"><ph name="VALUE">$1<ex>12</ex></ph>% more expensive than CoinGecko</message>
|
||||
<message name="IDS_BRAVE_SWAP_API" desc="Application Programming Interface (API)">API</message>
|
||||
<message name="IDS_BRAVE_SWAP_NAME" desc="Name">Name</message>
|
||||
<message name="IDS_BRAVE_SWAP_CONNECT_WALLET" desc="Connect wallet button text">Connect Wallet</message>
|
||||
<message name="IDS_BRAVE_SWAP_DISCONNECT_WALLET" desc="Disconnect wallet">Disconnect</message>
|
||||
<message name="IDS_BRAVE_SWAP_SWITCH_NETWORK" desc="Switch network button text">Switch Network</message>
|
||||
<message name="IDS_BRAVE_SWAP_ADVANCED" desc="Advanced quote details">Advanced</message>
|
||||
<message name="IDS_BRAVE_SWAP_ACCOUNTS" desc="Accounts">Accounts</message>
|
||||
<message name="IDS_BRAVE_SWAP_WALLET" desc="Wallet">Wallet</message>
|
||||
<message name="IDS_BRAVE_SWAP_BEST" desc="Best quote option">Best</message>
|
||||
<message name="IDS_BRAVE_SWAP_HELP_CENTER" desc="Help center">Help Center</message>
|
||||
<message name="IDS_BRAVE_SWAP_PRIVACY_POLICY" desc="Privacy policy">Privacy Policy</message>
|
||||
<message name="IDS_BRAVE_SWAP_PRIVACY_DESCRIPTION" desc="Privacy policy description">This app uses the following third-party APIs:</message>
|
||||
<message name="IDS_BRAVE_SWAP_ZERO_EX_DISCLAIMER" desc="0x swap privacy policy disclaimer">Brave Swap uses 0x as a DEX aggregator for supported EVM networks. 0x will process the Ethereum wallet address and IP address to fulfill a transaction (including getting quotes). 0x will ONLY use this data for the purposes of processing transactions.</message>
|
||||
<message name="IDS_BRAVE_SWAP_JUPITER_DISCLAIMER" desc="Jupiter swap privacy policy disclaimer">Brave Swap uses Jupiter as a DEX aggregator for Solana network. Jupiter will process the Solana wallet address and IP address to fulfill a transaction (including getting quotes). Jupiter will ONLY use this data for the purposes of processing transactions.</message>
|
||||
<message name="IDS_BRAVE_SWAP_ZERO_EX_PRIVACY" desc="0x swap full privacy policy link text">Click here for 0x Privacy Policy.</message>
|
||||
<message name="IDS_BRAVE_SWAP_JUPITER_PRIVACY" desc="Jupiter swap full privacy policy link text">Click here for Jupiter Privacy Policy.</message>
|
||||
</grit-part>
|
||||
|
||||
Generated
+6126
-83
File diff suppressed because it is too large
Load Diff
@@ -294,6 +294,7 @@
|
||||
"acorn": "8.0.5",
|
||||
"babel-loader": "8.2.3",
|
||||
"brave-ui": "github:brave/brave-ui#e4c049880199ac652b8f69610b8b70d1cd6d906f",
|
||||
"@brave/swap-interface": "0.12.4",
|
||||
"chalk": "4.1.0",
|
||||
"commander": "2.20.3",
|
||||
"css-loader": "3.6.0",
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Brian Vaughn
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,3 @@
|
||||
Name: @brave/swap-interface
|
||||
URL: https://github.com/brave/swap
|
||||
License: MPL-2.0
|
||||
Reference in New Issue
Block a user