Skip to content

Commit

Permalink
Merge remote-tracking branch 'public/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
henryboldi committed Mar 30, 2022
2 parents 0758e42 + 53d8f6b commit 58934fd
Show file tree
Hide file tree
Showing 35 changed files with 438 additions and 346 deletions.
4 changes: 1 addition & 3 deletions .env.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ BLOCKNATIVE_API_KEY="f60816ff-da02-463f-87a6-67a09c6d53fa"
READ_REDUX_CACHE=true
WRITE_REDUX_CACHE=true
HIDE_EARN_PAGE=true
HIDE_SEND_BUTTON=false
HIDE_ADD_SEED=false
HIDE_SWAP=false
HIDE_IMPORT_DERIVATION_PATH=true
HIDE_CREATE_PHRASE=false
HIDE_IMPORT_LEDGER=false
Expand All @@ -18,4 +16,4 @@ USE_MAINNET_FORK=false
MAINNET_FORK_URL="http://127.0.0.1:8545"
MAINNET_FORK_CHAIN_ID=1337
FILE_DIRECTORY_IPFS_HASH="QmYwYkRdYMBCtMqbimgaXjf7UL4RUb5zBQu4TDE67oZbq5"
PART_GLOSSARY_IPFS_HASH="bafybeibytsozn7qsvqgecogv5urg5en34r7v3zxo326vacumi56ckah5b4"
PART_GLOSSARY_IPFS_HASH="bafybeibytsozn7qsvqgecogv5urg5en34r7v3zxo326vacumi56ckah5b4"
2 changes: 0 additions & 2 deletions background/features/features.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export const HIDE_ADD_SEED = process.env.HIDE_ADD_SEED === "true"
export const HIDE_SEND_BUTTON = process.env.HIDE_SEND_BUTTON === "true"
export const HIDE_EARN_PAGE = process.env.HIDE_EARN_PAGE === "true"
export const HIDE_SWAP = process.env.HIDE_SWAP === "true"
export const HIDE_IMPORT_DERIVATION_PATH =
process.env.HIDE_IMPORT_DERIVATION_PATH === "true"
export const HIDE_CREATE_PHRASE = process.env.HIDE_CREATE_PHRASE === "true"
Expand Down
1 change: 0 additions & 1 deletion background/lib/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ function logLabelFromStackEntry(
return stackEntry
.split(WEBKIT_GECKO_DELIMITER)[0]
.split(GECKO_MARKER)
.reverse()
.filter((item) => item.replace(/(?:promise)?</, "").trim() !== "")
.slice(-2)
.join(".")
Expand Down
42 changes: 27 additions & 15 deletions background/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ import {
estimatedFeesPerGas,
emitter as transactionConstructionSliceEmitter,
transactionRequest,
signed,
updateTransactionOptions,
clearTransactionState,
selectDefaultNetworkFeeSettings,
TransactionConstructionStatus,
rejectTransactionSignature,
transactionSigned,
} from "./redux-slices/transaction-construction"
import { allAliases } from "./redux-slices/utils"
import {
Expand Down Expand Up @@ -117,7 +117,7 @@ const devToolsSanitizer = (input: unknown) => {

// The version of persisted Redux state the extension is expecting. Any previous
// state without this version, or with a lower version, ought to be migrated.
const REDUX_STATE_VERSION = 5
const REDUX_STATE_VERSION = 6

type Migration = (prevState: Record<string, unknown>) => Record<string, unknown>

Expand Down Expand Up @@ -210,6 +210,13 @@ const REDUX_MIGRATIONS: { [version: number]: Migration } = {
const { ...newState } = prevState
newState.keyrings.keyringMetadata = {}

return newState
},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6: (prevState: any) => {
const { ...newState } = prevState
newState.ledger.isArbitraryDataSigningEnabled = false

return newState
},
}
Expand Down Expand Up @@ -731,14 +738,17 @@ export default class Main extends BaseService<never> {
await this.chainService.populateEVMTransactionNonce(transaction)

try {
const signedTx = await this.keyringService.signTransaction(
{
address: transaction.from,
network: this.chainService.ethereumNetwork,
},
transactionWithNonce
const signedTransactionResult =
await this.keyringService.signTransaction(
{
address: transaction.from,
network: this.chainService.ethereumNetwork,
},
transactionWithNonce
)
await this.store.dispatch(
transactionSigned(signedTransactionResult)
)
this.store.dispatch(signed(signedTx))
} catch (exception) {
logger.error(
"Error signing transaction; releasing nonce",
Expand All @@ -748,11 +758,11 @@ export default class Main extends BaseService<never> {
}
} else {
try {
const signedTx = await this.signingService.signTransaction(
transaction,
method
const signedTransactionResult =
await this.signingService.signTransaction(transaction, method)
await this.store.dispatch(
transactionSigned(signedTransactionResult)
)
this.store.dispatch(signed(signedTx))
} catch (exception) {
logger.error("Error signing transaction", exception)
this.store.dispatch(
Expand Down Expand Up @@ -1015,9 +1025,11 @@ export default class Main extends BaseService<never> {
}
}

const resolveAndClear = (signedTransaction: SignedEVMTransaction) => {
const resolveAndClear = (
signedTransactionResult: SignedEVMTransaction
) => {
clear()
resolver(signedTransaction)
resolver(signedTransactionResult)
}

const rejectAndClear = () => {
Expand Down
18 changes: 12 additions & 6 deletions background/redux-slices/0x-swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ export const initialState: SwapState = {
inProgressApprovalContract: undefined,
}

// The magic string used by the 0x API to signify we're dealing with ETH rather
// than an ERC-20
const ZEROX_ETH_SIGNIFIER = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"

const swapSlice = createSlice({
name: "0x-swap",
initialState,
Expand Down Expand Up @@ -132,7 +128,7 @@ const gatedHeaders: { [header: string]: string } =
function build0xUrlFromSwapRequest(
requestPath: string,
{ assets, amount, slippageTolerance, gasPrice }: SwapQuoteRequest,
additionalParameters?: Record<string, string>
additionalParameters: Record<string, string>
): URL {
const requestUrl = new URL(`https://${zeroXApiBase}/swap/v1${requestPath}`)
const tradeAmount = utils.parseUnits(
Expand Down Expand Up @@ -165,6 +161,16 @@ function build0xUrlFromSwapRequest(
...gatedParameters,
...additionalParameters,
}).forEach(([parameter, value]) => {
// Do not set buyTokenPercentageFee if swapping to ETH. Currently the 0x
// `GET /quote` endpoint does not support a `sellTokenPercentageFee` and
// errors when passing in a `buyTokenPercentageFee` when the buy token is
// ETH.
if (
buyToken === "ETH" &&
(parameter === "buyTokenPercentageFee" || parameter === "feeRecipient")
) {
return
}
requestUrl.searchParams.set(parameter, value.toString())
})

Expand Down Expand Up @@ -249,7 +255,7 @@ export const fetchSwapPrice = createBackgroundAsyncThunk(
let needsApproval = false
// If we aren't selling ETH, check whether we need an approval to swap
// TODO Handle other non-ETH base assets
if (quote.sellTokenAddress !== ZEROX_ETH_SIGNIFIER) {
if (quote.allowanceTarget !== ethers.constants.AddressZero) {
const assetContract = new ethers.Contract(
quote.sellTokenAddress,
ERC20_ABI,
Expand Down
81 changes: 80 additions & 1 deletion background/redux-slices/assets.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { createSelector, createSlice } from "@reduxjs/toolkit"
import { AnyAsset, PricePoint } from "../assets"
import { ethers } from "ethers"
import {
AnyAsset,
AnyAssetAmount,
isSmartContractFungibleAsset,
PricePoint,
} from "../assets"
import { AddressOnNetwork } from "../accounts"
import { findClosestAssetIndex } from "../lib/asset-similarity"
import { normalizeEVMAddress } from "../lib/utils"
import { createBackgroundAsyncThunk } from "./utils"
import { isNetworkBaseAsset } from "./utils/asset-utils"
import { getProvider } from "./utils/contract-utils"
import { sameNetwork } from "../networks"
import { ERC20_INTERFACE } from "../lib/erc20"
import logger from "../lib/logger"

type SingleAssetState = AnyAsset & {
prices: PricePoint[]
Expand Down Expand Up @@ -145,6 +158,72 @@ const selectPairedAssetSymbol = (
pairedAssetSymbol: string
) => pairedAssetSymbol

/**
* Executes an asset transfer between two addresses, for a set amount. Supports
* an optional fixed gas limit.
*
* If the from address is not a writeable address in the wallet, this signature
* will not be possible.
*/
export const transferAsset = createBackgroundAsyncThunk(
"assets/transferAsset",
async ({
fromAddressNetwork: { address: fromAddress, network: fromNetwork },
toAddressNetwork: { address: toAddress, network: toNetwork },
assetAmount,
gasLimit,
}: {
fromAddressNetwork: AddressOnNetwork
toAddressNetwork: AddressOnNetwork
assetAmount: AnyAssetAmount
gasLimit: bigint | undefined
}) => {
if (!sameNetwork(fromNetwork, toNetwork)) {
throw new Error("Only same-network transfers are supported for now.")
}

const provider = getProvider()
const signer = provider.getSigner()

if (isNetworkBaseAsset(assetAmount.asset, fromNetwork)) {
logger.debug(
`Sending ${assetAmount.amount} ${assetAmount.asset.symbol} from ` +
`${fromAddress} to ${toAddress} as a base asset transfer.`
)
await signer.sendTransaction({
from: fromAddress,
to: toAddress,
value: assetAmount.amount,
gasLimit,
})
} else if (isSmartContractFungibleAsset(assetAmount.asset)) {
logger.debug(
`Sending ${assetAmount.amount} ${assetAmount.asset.symbol} from ` +
`${fromAddress} to ${toAddress} as an ERC20 transfer.`
)
const token = new ethers.Contract(
assetAmount.asset.contractAddress,
ERC20_INTERFACE,
signer
)

const transactionDetails = await token.populateTransaction.transfer(
toAddress,
assetAmount.amount
)

await signer.sendUncheckedTransaction({
...transactionDetails,
gasLimit: gasLimit ?? transactionDetails.gasLimit,
})
} else {
throw new Error(
"Only base and fungible smart contract asset transfers are supported for now."
)
}
}
)

/**
* Selects a particular asset price point given the asset symbol and the paired
* asset symbol used to price it.
Expand Down
40 changes: 29 additions & 11 deletions background/redux-slices/transaction-construction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ export enum NetworkFeeTypeChosen {
}
export type TransactionConstruction = {
status: TransactionConstructionStatus
// @TODO Check if this can still be both types
transactionRequest?:
| EIP1559TransactionRequest
| EnrichedEIP1559TransactionRequest
transactionRequest?: EnrichedEIP1559TransactionRequest
signedTransaction?: SignedEVMTransaction
broadcastOnSign?: boolean
transactionLikelyFails?: boolean
Expand Down Expand Up @@ -106,13 +103,6 @@ export const signTransaction = createBackgroundAsyncThunk(
}
)

export const broadcastSignedTransaction = createBackgroundAsyncThunk(
"transaction-construction/broadcast",
async (transaction: SignedEVMTransaction) => {
await emitter.emit("broadcastSignedTransaction", transaction)
}
)

const transactionSlice = createSlice({
name: "transaction-construction",
initialState,
Expand Down Expand Up @@ -252,6 +242,28 @@ export const {

export default transactionSlice.reducer

export const broadcastSignedTransaction = createBackgroundAsyncThunk(
"transaction-construction/broadcast",
async (transaction: SignedEVMTransaction) => {
await emitter.emit("broadcastSignedTransaction", transaction)
}
)

export const transactionSigned = createBackgroundAsyncThunk(
"transaction-construction/transaction-signed",
async (transaction: SignedEVMTransaction, { dispatch, getState }) => {
await dispatch(signed(transaction))

const { transactionConstruction } = getState() as {
transactionConstruction: TransactionConstruction
}

if (transactionConstruction.broadcastOnSign ?? false) {
await dispatch(broadcastSignedTransaction(transaction))
}
}
)

export const rejectTransactionSignature = createBackgroundAsyncThunk(
"transaction-construction/reject",
async (_, { dispatch }) => {
Expand Down Expand Up @@ -313,6 +325,12 @@ export const selectTransactionData = createSelector(
(transactionRequestData) => transactionRequestData
)

export const selectIsTransactionPendingSignature = createSelector(
(state: { transactionConstruction: TransactionConstruction }) =>
state.transactionConstruction.status,
(status) => status === "loaded" || status === "pending"
)

export const selectIsTransactionLoaded = createSelector(
(state: { transactionConstruction: TransactionConstruction }) =>
state.transactionConstruction.status,
Expand Down
24 changes: 24 additions & 0 deletions background/redux-slices/utils/asset-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import {
PricePoint,
FungibleAsset,
UnitPricePoint,
AnyAsset,
} from "../../assets"
import { fromFixedPointNumber } from "../../lib/fixed-point"
import { AnyNetwork } from "../../networks"

/**
* Adds user-specific amounts based on preferences. This is the combination of
Expand All @@ -33,6 +35,28 @@ export type AssetDecimalAmount = {
localizedDecimalAmount: string
}

/**
* Given an asset and a network, determines whether the given asset is the base
* asset for the given network. Used to special-case transactions that should
* work differently for base assets vs, for example, smart contract assets.
*
* @param asset The asset that could be a base asset for a network.
* @param network The network whose base asset `asset` should be checked against.
*
* @return True if the passed asset is the base asset for the passed network.
*/
export function isNetworkBaseAsset(
asset: AnyAsset,
network: AnyNetwork
): boolean {
return (
!("homeNetwork" in asset) &&
"family" in network &&
network.family === "EVM" &&
asset.symbol === network.baseAsset.symbol
)
}

/**
* Given an asset symbol, price as a JavaScript number, and a number of desired
* decimals during formatting, format the price in a localized way as a
Expand Down

0 comments on commit 58934fd

Please sign in to comment.