Merge pull request #10513 from MetaMask/Version-v9.1.0
commit
2e88bd243d
@ -0,0 +1,17 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
set -x |
||||||
|
set -e |
||||||
|
set -u |
||||||
|
set -o pipefail |
||||||
|
|
||||||
|
BUILD_DEST="./build-artifacts/build-viz/" |
||||||
|
|
||||||
|
# prepare artifacts dir |
||||||
|
mkdir -p "${BUILD_DEST}" |
||||||
|
|
||||||
|
# generate lavamoat debug config |
||||||
|
yarn lavamoat:debug |
||||||
|
|
||||||
|
# generate viz |
||||||
|
npx lavamoat-viz --dest "${BUILD_DEST}" |
@ -0,0 +1,15 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
set -e |
||||||
|
set -u |
||||||
|
set -o pipefail |
||||||
|
|
||||||
|
yarn allow-scripts auto |
||||||
|
|
||||||
|
if git diff --exit-code --quiet |
||||||
|
then |
||||||
|
echo "allow-scripts configuration is up-to-date" |
||||||
|
else |
||||||
|
echo "allow-scripts configuration requires updates" |
||||||
|
exit 1 |
||||||
|
fi |
@ -0,0 +1,15 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
set -e |
||||||
|
set -u |
||||||
|
set -o pipefail |
||||||
|
|
||||||
|
yarn lavamoat:auto |
||||||
|
|
||||||
|
if git diff --exit-code --quiet |
||||||
|
then |
||||||
|
echo "LavaMoat policy is up-to-date" |
||||||
|
else |
||||||
|
echo "LavaMoat policy requires updates" |
||||||
|
exit 1 |
||||||
|
fi |
@ -0,0 +1,37 @@ |
|||||||
|
// import { useGlobals } from '@storybook/api';
|
||||||
|
const { useGlobals } = require('@storybook/api') |
||||||
|
const React = require("react") |
||||||
|
const { addons, types } = require("@storybook/addons") |
||||||
|
const { Icons, IconButton } = require('@storybook/components') |
||||||
|
const localeList = require('../../app/_locales/index.json') |
||||||
|
const { useEffect } = React |
||||||
|
|
||||||
|
addons.register("i18n-party", () => { |
||||||
|
|
||||||
|
addons.add("i18n-party", { |
||||||
|
title: "rotates through every i18n locale", |
||||||
|
//👇 Sets the type of UI element in Storybook
|
||||||
|
type: types.TOOL, |
||||||
|
match: () => true, |
||||||
|
render: (...args) => { |
||||||
|
// https://github.com/storybookjs/storybook/blob/6490a0d646dbaa293b76bbde477daca615efe789/addons/toolbars/src/components/MenuToolbar.tsx#L2
|
||||||
|
const [globals, updateGlobals] = useGlobals() |
||||||
|
useEffect(() => { |
||||||
|
if (!globals.localeParty) return |
||||||
|
const interval = setInterval((...args) => { |
||||||
|
const currentIndex = localeList.findIndex(({ code }) => code === globals.locale) |
||||||
|
const nextIndex = (currentIndex + 1) % localeList.length |
||||||
|
const nextLocale = localeList[nextIndex].code |
||||||
|
updateGlobals({ locale: nextLocale }) |
||||||
|
}, 2000) |
||||||
|
return () => clearInterval(interval) |
||||||
|
}) |
||||||
|
|
||||||
|
return ( |
||||||
|
<IconButton onClick={() => updateGlobals({ localeParty: !globals.localeParty })}> |
||||||
|
<Icons icon={globals.localeParty ? 'star' : 'starhollow'}/> |
||||||
|
</IconButton> |
||||||
|
) |
||||||
|
}, |
||||||
|
}) |
||||||
|
}) |
@ -0,0 +1,218 @@ |
|||||||
|
import { TRANSACTION_STATUSES } from '../shared/constants/transaction'; |
||||||
|
|
||||||
|
const state = { |
||||||
|
metamask: { |
||||||
|
isInitialized: true, |
||||||
|
isUnlocked: true, |
||||||
|
featureFlags: { sendHexData: true }, |
||||||
|
rpcUrl: 'https://rawtestrpc.metamask.io/', |
||||||
|
identities: { |
||||||
|
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': { |
||||||
|
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', |
||||||
|
name: 'Send Account 1', |
||||||
|
}, |
||||||
|
'0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': { |
||||||
|
address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', |
||||||
|
name: 'Send Account 2', |
||||||
|
}, |
||||||
|
'0x2f8d4a878cfa04a6e60d46362f5644deab66572d': { |
||||||
|
address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', |
||||||
|
name: 'Send Account 3', |
||||||
|
}, |
||||||
|
'0xd85a4b6a394794842887b8284293d69163007bbb': { |
||||||
|
address: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
name: 'Send Account 4', |
||||||
|
}, |
||||||
|
}, |
||||||
|
cachedBalances: {}, |
||||||
|
currentBlockGasLimit: '0x4c1878', |
||||||
|
currentCurrency: 'USD', |
||||||
|
conversionRate: 1200.88200327, |
||||||
|
conversionDate: 1489013762, |
||||||
|
nativeCurrency: 'ETH', |
||||||
|
frequentRpcList: [], |
||||||
|
network: '3', |
||||||
|
provider: { |
||||||
|
type: 'ropsten', |
||||||
|
chainId: '0x3', |
||||||
|
}, |
||||||
|
accounts: { |
||||||
|
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': { |
||||||
|
code: '0x', |
||||||
|
balance: '0x47c9d71831c76efe', |
||||||
|
nonce: '0x1b', |
||||||
|
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825', |
||||||
|
}, |
||||||
|
'0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb': { |
||||||
|
code: '0x', |
||||||
|
balance: '0x37452b1315889f80', |
||||||
|
nonce: '0xa', |
||||||
|
address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', |
||||||
|
}, |
||||||
|
'0x2f8d4a878cfa04a6e60d46362f5644deab66572d': { |
||||||
|
code: '0x', |
||||||
|
balance: '0x30c9d71831c76efe', |
||||||
|
nonce: '0x1c', |
||||||
|
address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', |
||||||
|
}, |
||||||
|
'0xd85a4b6a394794842887b8284293d69163007bbb': { |
||||||
|
code: '0x', |
||||||
|
balance: '0x0', |
||||||
|
nonce: '0x0', |
||||||
|
address: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
}, |
||||||
|
}, |
||||||
|
addressBook: { |
||||||
|
'0x3': { |
||||||
|
'0x06195827297c7a80a443b6894d3bdb8824b43896': { |
||||||
|
address: '0x06195827297c7a80a443b6894d3bdb8824b43896', |
||||||
|
name: 'Address Book Account 1', |
||||||
|
chainId: '0x3', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
tokens: [ |
||||||
|
{ |
||||||
|
address: '0x1a195821297c7a80a433b6894d3bdb8824b43896', |
||||||
|
decimals: 18, |
||||||
|
symbol: 'ABC', |
||||||
|
}, |
||||||
|
{ |
||||||
|
address: '0x8d6b81208414189a58339873ab429b6c47ab92d3', |
||||||
|
decimals: 4, |
||||||
|
symbol: 'DEF', |
||||||
|
}, |
||||||
|
{ |
||||||
|
address: '0xa42084c8d1d9a2198631988579bb36b48433a72b', |
||||||
|
decimals: 18, |
||||||
|
symbol: 'GHI', |
||||||
|
}, |
||||||
|
], |
||||||
|
transactions: {}, |
||||||
|
currentNetworkTxList: [ |
||||||
|
{ |
||||||
|
id: 'mockTokenTx1', |
||||||
|
txParams: { |
||||||
|
to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', |
||||||
|
from: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
}, |
||||||
|
time: 1700000000000, |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'mockTokenTx2', |
||||||
|
txParams: { |
||||||
|
to: '0xafaketokenaddress', |
||||||
|
from: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
}, |
||||||
|
time: 1600000000000, |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'mockTokenTx3', |
||||||
|
txParams: { |
||||||
|
to: '0x8d6b81208414189a58339873ab429b6c47ab92d3', |
||||||
|
from: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
}, |
||||||
|
time: 1500000000000, |
||||||
|
}, |
||||||
|
{ |
||||||
|
id: 'mockEthTx1', |
||||||
|
txParams: { |
||||||
|
to: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
from: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
}, |
||||||
|
time: 1400000000000, |
||||||
|
}, |
||||||
|
], |
||||||
|
unapprovedMsgs: { |
||||||
|
'0xabc': { id: 'unapprovedMessage1', time: 1650000000000 }, |
||||||
|
'0xdef': { id: 'unapprovedMessage2', time: 1550000000000 }, |
||||||
|
'0xghi': { id: 'unapprovedMessage3', time: 1450000000000 }, |
||||||
|
}, |
||||||
|
unapprovedMsgCount: 0, |
||||||
|
unapprovedPersonalMsgs: {}, |
||||||
|
unapprovedPersonalMsgCount: 0, |
||||||
|
unapprovedDecryptMsgs: {}, |
||||||
|
unapprovedDecryptMsgCount: 0, |
||||||
|
unapprovedEncryptionPublicKeyMsgs: {}, |
||||||
|
unapprovedEncryptionPublicKeyMsgCount: 0, |
||||||
|
keyringTypes: ['Simple Key Pair', 'HD Key Tree'], |
||||||
|
keyrings: [ |
||||||
|
{ |
||||||
|
type: 'HD Key Tree', |
||||||
|
accounts: [ |
||||||
|
'fdea65c8e26263f6d9a1b5de9555d2931a33b825', |
||||||
|
'c5b8dbac4c1d3f152cdeb400e2313f309c410acb', |
||||||
|
'2f8d4a878cfa04a6e60d46362f5644deab66572d', |
||||||
|
], |
||||||
|
}, |
||||||
|
{ |
||||||
|
type: 'Simple Key Pair', |
||||||
|
accounts: ['0xd85a4b6a394794842887b8284293d69163007bbb'], |
||||||
|
}, |
||||||
|
], |
||||||
|
selectedAddress: '0xd85a4b6a394794842887b8284293d69163007bbb', |
||||||
|
send: { |
||||||
|
gasLimit: '0xFFFF', |
||||||
|
gasPrice: '0xaa', |
||||||
|
gasTotal: '0xb451dc41b578', |
||||||
|
tokenBalance: 3434, |
||||||
|
from: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', |
||||||
|
to: '0x987fedabc', |
||||||
|
amount: '0x080', |
||||||
|
memo: '', |
||||||
|
errors: { |
||||||
|
someError: null, |
||||||
|
}, |
||||||
|
maxModeOn: false, |
||||||
|
editingTransactionId: 97531, |
||||||
|
}, |
||||||
|
unapprovedTxs: { |
||||||
|
4768706228115573: { |
||||||
|
id: 4768706228115573, |
||||||
|
time: 1487363153561, |
||||||
|
status: TRANSACTION_STATUSES.UNAPPROVED, |
||||||
|
gasMultiplier: 1, |
||||||
|
metamaskNetworkId: '3', |
||||||
|
txParams: { |
||||||
|
from: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb', |
||||||
|
to: '0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761', |
||||||
|
value: '0xde0b6b3a7640000', |
||||||
|
metamaskId: 4768706228115573, |
||||||
|
metamaskNetworkId: '3', |
||||||
|
gas: '0x5209', |
||||||
|
}, |
||||||
|
txFee: '17e0186e60800', |
||||||
|
txValue: 'de0b6b3a7640000', |
||||||
|
maxCost: 'de234b52e4a0800', |
||||||
|
gasPrice: '4a817c800', |
||||||
|
}, |
||||||
|
}, |
||||||
|
currentLocale: 'en', |
||||||
|
}, |
||||||
|
appState: { |
||||||
|
menuOpen: false, |
||||||
|
currentView: { |
||||||
|
name: 'accountDetail', |
||||||
|
detailView: null, |
||||||
|
context: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', |
||||||
|
}, |
||||||
|
accountDetail: { |
||||||
|
subview: 'transactions', |
||||||
|
}, |
||||||
|
modal: { |
||||||
|
modalState: {}, |
||||||
|
previousModalState: {}, |
||||||
|
}, |
||||||
|
isLoading: false, |
||||||
|
warning: null, |
||||||
|
scrollToBottom: false, |
||||||
|
forgottenPassword: null, |
||||||
|
}, |
||||||
|
send: { |
||||||
|
fromDropdownOpen: false, |
||||||
|
toDropdownOpen: false, |
||||||
|
errors: { someError: null }, |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
export default state; |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1 +1 @@ |
|||||||
export { default } from './network'; |
export { default, NETWORK_EVENTS } from './network'; |
||||||
|
@ -0,0 +1,272 @@ |
|||||||
|
import { ethErrors } from 'eth-rpc-errors'; |
||||||
|
import validUrl from 'valid-url'; |
||||||
|
import { omit } from 'lodash'; |
||||||
|
import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; |
||||||
|
import { |
||||||
|
isPrefixedFormattedHexString, |
||||||
|
isSafeChainId, |
||||||
|
} from '../../../../../shared/modules/network.utils'; |
||||||
|
import { jsonRpcRequest } from '../../../../../shared/modules/rpc.utils'; |
||||||
|
import { CHAIN_ID_TO_NETWORK_ID_MAP } from '../../../../../shared/constants/network'; |
||||||
|
|
||||||
|
const addEthereumChain = { |
||||||
|
methodNames: [MESSAGE_TYPE.ADD_ETHEREUM_CHAIN], |
||||||
|
implementation: addEthereumChainHandler, |
||||||
|
}; |
||||||
|
export default addEthereumChain; |
||||||
|
|
||||||
|
async function addEthereumChainHandler( |
||||||
|
req, |
||||||
|
res, |
||||||
|
_next, |
||||||
|
end, |
||||||
|
{ |
||||||
|
addCustomRpc, |
||||||
|
getCurrentChainId, |
||||||
|
findCustomRpcBy, |
||||||
|
updateRpcTarget, |
||||||
|
requestUserApproval, |
||||||
|
sendMetrics, |
||||||
|
}, |
||||||
|
) { |
||||||
|
if (!req.params?.[0] || typeof req.params[0] !== 'object') { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected single, object parameter. Received:\n${JSON.stringify( |
||||||
|
req.params, |
||||||
|
)}`,
|
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const { origin } = req; |
||||||
|
|
||||||
|
const { |
||||||
|
chainId, |
||||||
|
chainName = null, |
||||||
|
blockExplorerUrls = null, |
||||||
|
nativeCurrency = null, |
||||||
|
rpcUrls, |
||||||
|
} = req.params[0]; |
||||||
|
|
||||||
|
const otherKeys = Object.keys( |
||||||
|
omit(req.params[0], [ |
||||||
|
'chainId', |
||||||
|
'chainName', |
||||||
|
'blockExplorerUrls', |
||||||
|
'iconUrls', |
||||||
|
'rpcUrls', |
||||||
|
'nativeCurrency', |
||||||
|
]), |
||||||
|
); |
||||||
|
|
||||||
|
if (otherKeys.length > 0) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Received unexpected keys on object parameter. Unsupported keys:\n${otherKeys}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const firstValidRPCUrl = Array.isArray(rpcUrls) |
||||||
|
? rpcUrls.find((rpcUrl) => validUrl.isHttpsUri(rpcUrl)) |
||||||
|
: null; |
||||||
|
|
||||||
|
const firstValidBlockExplorerUrl = |
||||||
|
blockExplorerUrls !== null && Array.isArray(blockExplorerUrls) |
||||||
|
? blockExplorerUrls.find((blockExplorerUrl) => |
||||||
|
validUrl.isHttpsUri(blockExplorerUrl), |
||||||
|
) |
||||||
|
: null; |
||||||
|
|
||||||
|
if (!firstValidRPCUrl) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected an array with at least one valid string HTTPS url 'rpcUrls', Received:\n${rpcUrls}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (blockExplorerUrls !== null && !firstValidBlockExplorerUrl) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected null or array with at least one valid string HTTPS URL 'blockExplorerUrl'. Received: ${blockExplorerUrls}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const _chainId = typeof chainId === 'string' && chainId.toLowerCase(); |
||||||
|
|
||||||
|
if (!isPrefixedFormattedHexString(_chainId)) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected 0x-prefixed, unpadded, non-zero hexadecimal string 'chainId'. Received:\n${chainId}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (!isSafeChainId(parseInt(_chainId, 16))) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Invalid chain ID "${_chainId}": numerical value greater than max safe value. Received:\n${chainId}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (CHAIN_ID_TO_NETWORK_ID_MAP[_chainId]) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `May not specify default MetaMask chain.`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const existingNetwork = findCustomRpcBy({ chainId: _chainId }); |
||||||
|
|
||||||
|
if (existingNetwork !== null) { |
||||||
|
const currentChainId = getCurrentChainId(); |
||||||
|
if (currentChainId === _chainId) { |
||||||
|
res.result = null; |
||||||
|
return end(); |
||||||
|
} |
||||||
|
try { |
||||||
|
await updateRpcTarget( |
||||||
|
await requestUserApproval({ |
||||||
|
origin, |
||||||
|
type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, |
||||||
|
requestData: { |
||||||
|
rpcUrl: existingNetwork.rpcUrl, |
||||||
|
chainId: existingNetwork.chainId, |
||||||
|
nickname: existingNetwork.nickname, |
||||||
|
ticker: existingNetwork.ticker, |
||||||
|
}, |
||||||
|
}), |
||||||
|
); |
||||||
|
res.result = null; |
||||||
|
} catch (error) { |
||||||
|
return end(error); |
||||||
|
} |
||||||
|
return end(); |
||||||
|
} |
||||||
|
|
||||||
|
let endpointChainId; |
||||||
|
|
||||||
|
try { |
||||||
|
endpointChainId = await jsonRpcRequest(firstValidRPCUrl, 'eth_chainId'); |
||||||
|
} catch (err) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.internal({ |
||||||
|
message: `Request for method 'eth_chainId on ${firstValidRPCUrl} failed`, |
||||||
|
data: { networkErr: err }, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (_chainId !== endpointChainId) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Chain ID returned by RPC URL ${firstValidRPCUrl} does not match ${_chainId}`, |
||||||
|
data: { chainId: endpointChainId }, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (typeof chainName !== 'string' || !chainName) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected non-empty string 'chainName'. Received:\n${chainName}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
const _chainName = |
||||||
|
chainName.length > 100 ? chainName.substring(0, 100) : chainName; |
||||||
|
|
||||||
|
if (nativeCurrency !== null) { |
||||||
|
if (typeof nativeCurrency !== 'object' || Array.isArray(nativeCurrency)) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected null or object 'nativeCurrency'. Received:\n${nativeCurrency}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
if (nativeCurrency.decimals !== 18) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected the number 18 for 'nativeCurrency.decimals' when 'nativeCurrency' is provided. Received: ${nativeCurrency.decimals}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
if (!nativeCurrency.symbol || typeof nativeCurrency.symbol !== 'string') { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected a string 'nativeCurrency.symbol'. Received: ${nativeCurrency.symbol}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
const ticker = nativeCurrency?.symbol || 'ETH'; |
||||||
|
|
||||||
|
if (typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6) { |
||||||
|
return end( |
||||||
|
ethErrors.rpc.invalidParams({ |
||||||
|
message: `Expected 2-6 character string 'nativeCurrency.symbol'. Received:\n${ticker}`, |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
await addCustomRpc( |
||||||
|
await requestUserApproval({ |
||||||
|
origin, |
||||||
|
type: MESSAGE_TYPE.ADD_ETHEREUM_CHAIN, |
||||||
|
requestData: { |
||||||
|
chainId: _chainId, |
||||||
|
blockExplorerUrl: firstValidBlockExplorerUrl, |
||||||
|
chainName: _chainName, |
||||||
|
rpcUrl: firstValidRPCUrl, |
||||||
|
ticker, |
||||||
|
}, |
||||||
|
}), |
||||||
|
); |
||||||
|
|
||||||
|
sendMetrics({ |
||||||
|
event: 'Custom Network Added', |
||||||
|
category: 'Network', |
||||||
|
referrer: { |
||||||
|
url: origin, |
||||||
|
}, |
||||||
|
sensitiveProperties: { |
||||||
|
chain_id: _chainId, |
||||||
|
rpc_url: firstValidRPCUrl, |
||||||
|
network_name: _chainName, |
||||||
|
// Including network to override the default network
|
||||||
|
// property included in all events. For RPC type networks
|
||||||
|
// the MetaMetrics controller uses the rpcUrl for the network
|
||||||
|
// property.
|
||||||
|
network: firstValidRPCUrl, |
||||||
|
symbol: ticker, |
||||||
|
block_explorer_url: firstValidBlockExplorerUrl, |
||||||
|
source: 'dapp', |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
await updateRpcTarget( |
||||||
|
await requestUserApproval({ |
||||||
|
origin, |
||||||
|
type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, |
||||||
|
requestData: { |
||||||
|
rpcUrl: firstValidRPCUrl, |
||||||
|
chainId: _chainId, |
||||||
|
nickname: _chainName, |
||||||
|
ticker, |
||||||
|
}, |
||||||
|
}), |
||||||
|
); |
||||||
|
|
||||||
|
res.result = null; |
||||||
|
} catch (error) { |
||||||
|
return end(error); |
||||||
|
} |
||||||
|
return end(); |
||||||
|
} |
@ -1,6 +1,12 @@ |
|||||||
|
import addEthereumChain from './add-ethereum-chain'; |
||||||
import getProviderState from './get-provider-state'; |
import getProviderState from './get-provider-state'; |
||||||
import logWeb3ShimUsage from './log-web3-shim-usage'; |
import logWeb3ShimUsage from './log-web3-shim-usage'; |
||||||
import watchAsset from './watch-asset'; |
import watchAsset from './watch-asset'; |
||||||
|
|
||||||
const handlers = [getProviderState, logWeb3ShimUsage, watchAsset]; |
const handlers = [ |
||||||
|
addEthereumChain, |
||||||
|
getProviderState, |
||||||
|
logWeb3ShimUsage, |
||||||
|
watchAsset, |
||||||
|
]; |
||||||
export default handlers; |
export default handlers; |
||||||
|
@ -0,0 +1,125 @@ |
|||||||
|
import { cloneDeep } from 'lodash'; |
||||||
|
import { |
||||||
|
GOERLI, |
||||||
|
GOERLI_CHAIN_ID, |
||||||
|
KOVAN, |
||||||
|
KOVAN_CHAIN_ID, |
||||||
|
MAINNET, |
||||||
|
MAINNET_CHAIN_ID, |
||||||
|
NETWORK_TYPE_RPC, |
||||||
|
RINKEBY, |
||||||
|
RINKEBY_CHAIN_ID, |
||||||
|
ROPSTEN, |
||||||
|
ROPSTEN_CHAIN_ID, |
||||||
|
} from '../../../shared/constants/network'; |
||||||
|
|
||||||
|
const version = 52; |
||||||
|
|
||||||
|
/** |
||||||
|
* Migrate tokens in Preferences to be keyed by chainId instead of |
||||||
|
* providerType. To prevent breaking user's MetaMask and selected |
||||||
|
* tokens, this migration copies the RPC entry into *every* custom RPC |
||||||
|
* chainId. |
||||||
|
*/ |
||||||
|
export default { |
||||||
|
version, |
||||||
|
async migrate(originalVersionedData) { |
||||||
|
const versionedData = cloneDeep(originalVersionedData); |
||||||
|
versionedData.meta.version = version; |
||||||
|
const state = versionedData.data; |
||||||
|
versionedData.data = transformState(state); |
||||||
|
return versionedData; |
||||||
|
}, |
||||||
|
}; |
||||||
|
|
||||||
|
function transformState(state = {}) { |
||||||
|
if (state.PreferencesController) { |
||||||
|
const { |
||||||
|
accountTokens, |
||||||
|
accountHiddenTokens, |
||||||
|
frequentRpcListDetail, |
||||||
|
} = state.PreferencesController; |
||||||
|
|
||||||
|
const newAccountTokens = {}; |
||||||
|
const newAccountHiddenTokens = {}; |
||||||
|
|
||||||
|
if (accountTokens && Object.keys(accountTokens).length > 0) { |
||||||
|
for (const address of Object.keys(accountTokens)) { |
||||||
|
newAccountTokens[address] = {}; |
||||||
|
if (accountTokens[address][NETWORK_TYPE_RPC]) { |
||||||
|
frequentRpcListDetail.forEach((detail) => { |
||||||
|
newAccountTokens[address][detail.chainId] = |
||||||
|
accountTokens[address][NETWORK_TYPE_RPC]; |
||||||
|
}); |
||||||
|
} |
||||||
|
for (const providerType of Object.keys(accountTokens[address])) { |
||||||
|
switch (providerType) { |
||||||
|
case MAINNET: |
||||||
|
newAccountTokens[address][MAINNET_CHAIN_ID] = |
||||||
|
accountTokens[address][MAINNET]; |
||||||
|
break; |
||||||
|
case ROPSTEN: |
||||||
|
newAccountTokens[address][ROPSTEN_CHAIN_ID] = |
||||||
|
accountTokens[address][ROPSTEN]; |
||||||
|
break; |
||||||
|
case RINKEBY: |
||||||
|
newAccountTokens[address][RINKEBY_CHAIN_ID] = |
||||||
|
accountTokens[address][RINKEBY]; |
||||||
|
break; |
||||||
|
case GOERLI: |
||||||
|
newAccountTokens[address][GOERLI_CHAIN_ID] = |
||||||
|
accountTokens[address][GOERLI]; |
||||||
|
break; |
||||||
|
case KOVAN: |
||||||
|
newAccountTokens[address][KOVAN_CHAIN_ID] = |
||||||
|
accountTokens[address][KOVAN]; |
||||||
|
break; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
state.PreferencesController.accountTokens = newAccountTokens; |
||||||
|
} |
||||||
|
|
||||||
|
if (accountHiddenTokens && Object.keys(accountHiddenTokens).length > 0) { |
||||||
|
for (const address of Object.keys(accountHiddenTokens)) { |
||||||
|
newAccountHiddenTokens[address] = {}; |
||||||
|
if (accountHiddenTokens[address][NETWORK_TYPE_RPC]) { |
||||||
|
frequentRpcListDetail.forEach((detail) => { |
||||||
|
newAccountHiddenTokens[address][detail.chainId] = |
||||||
|
accountHiddenTokens[address][NETWORK_TYPE_RPC]; |
||||||
|
}); |
||||||
|
} |
||||||
|
for (const providerType of Object.keys(accountHiddenTokens[address])) { |
||||||
|
switch (providerType) { |
||||||
|
case MAINNET: |
||||||
|
newAccountHiddenTokens[address][MAINNET_CHAIN_ID] = |
||||||
|
accountHiddenTokens[address][MAINNET]; |
||||||
|
break; |
||||||
|
case ROPSTEN: |
||||||
|
newAccountHiddenTokens[address][ROPSTEN_CHAIN_ID] = |
||||||
|
accountHiddenTokens[address][ROPSTEN]; |
||||||
|
break; |
||||||
|
case RINKEBY: |
||||||
|
newAccountHiddenTokens[address][RINKEBY_CHAIN_ID] = |
||||||
|
accountHiddenTokens[address][RINKEBY]; |
||||||
|
break; |
||||||
|
case GOERLI: |
||||||
|
newAccountHiddenTokens[address][GOERLI_CHAIN_ID] = |
||||||
|
accountHiddenTokens[address][GOERLI]; |
||||||
|
break; |
||||||
|
case KOVAN: |
||||||
|
newAccountHiddenTokens[address][KOVAN_CHAIN_ID] = |
||||||
|
accountHiddenTokens[address][KOVAN]; |
||||||
|
break; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
state.PreferencesController.accountHiddenTokens = newAccountHiddenTokens; |
||||||
|
} |
||||||
|
} |
||||||
|
return state; |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue