Skip to content

Commit

Permalink
Merge pull request #15762 from brave/f/wallet/swap-v2
Browse files Browse the repository at this point in the history
feat(swap): add Swap v2 integration
  • Loading branch information
onyb committed Nov 28, 2022
2 parents d3a5135 + 3b3f2f2 commit 1d42080
Show file tree
Hide file tree
Showing 20 changed files with 6,921 additions and 119 deletions.
67 changes: 66 additions & 1 deletion components/brave_wallet/browser/brave_wallet_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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/";
Expand Down
25 changes: 24 additions & 1 deletion components/brave_wallet/browser/swap_response_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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;
}

Expand Down
26 changes: 24 additions & 2 deletions components/brave_wallet/browser/swap_response_parser_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand Down
8 changes: 7 additions & 1 deletion components/brave_wallet/browser/swap_responses.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down
29 changes: 27 additions & 2 deletions components/brave_wallet/browser/swap_service_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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(
Expand Down Expand Up @@ -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();
Expand All @@ -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(
Expand Down
8 changes: 7 additions & 1 deletion components/brave_wallet/common/brave_wallet.mojom
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
8 changes: 6 additions & 2 deletions components/brave_wallet_ui/common/async/__mocks__/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export class MockedWalletApiProxy {
sellAmount: '124067000000000000',
allowanceTarget: '0x0000000000000000000000000000000000000000',
sellTokenToEthRate: '1',
buyTokenToEthRate: '1720.180416'
buyTokenToEthRate: '1720.180416',
estimatedPriceImpact: '0.0782',
sources: []
}

mockTransaction = {
Expand All @@ -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>> = {
Expand Down
13 changes: 11 additions & 2 deletions components/brave_wallet_ui/common/async/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit 1d42080

Please sign in to comment.