mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
conflict fixes
This commit is contained in:
parent
f1403f4849
commit
1739ed9710
@ -27,9 +27,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- [#11115](https://github.com/MetaMask/metamask-extension/pull/11115): Hide basic tab in advanced gas modal for speedup and cancel when on testnets
|
||||
- [#11030](https://github.com/MetaMask/metamask-extension/pull/11030): Return a specific error (code 4902) for switchEthereumChain requests for chains that aren't already in the user's wallet.
|
||||
- [#11093](https://github.com/MetaMask/metamask-extension/pull/11093): Update all uses of "Seed Phrase" to "Secret Recovery Phrase"
|
||||
## [9.5.9]
|
||||
### Added
|
||||
- Re-added "Add Ledger Live Support" ([#10293](https://github.com/MetaMask/metamask-extension/pull/10293)), which was reverted in the previous version
|
||||
|
||||
### Fixed
|
||||
- [#11025](https://github.com/MetaMask/metamask-extension/pull/11025): Fixed redirection to the build quotes page from the swaps page when failure has occured
|
||||
@ -45,6 +42,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- [#11031](https://github.com/MetaMask/metamask-extension/pull/11031): Fixes error behavior of addEthereumChain
|
||||
|
||||
## [9.5.9]
|
||||
### Added
|
||||
- Re-added "Add Ledger Live Support" ([#10293](https://github.com/MetaMask/metamask-extension/pull/10293)), which was reverted in the previous version
|
||||
|
||||
### Fixed
|
||||
- [#11225](https://github.com/MetaMask/metamask-extension/pull/11225) - Fix persistent display of chrome ledger What's New popup message
|
||||
|
||||
|
@ -191,9 +191,4 @@ describe('ComposableObservableStore', function () {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should return empty flattened state when not configured', function () {
|
||||
const store = new ComposableObservableStore();
|
||||
assert.deepEqual(store.getFlatState(), {});
|
||||
});
|
||||
});
|
||||
|
@ -14,7 +14,6 @@ import { getTranslatedUINoficiations } from '../../../../shared/notifications';
|
||||
import { getSortedNotificationsToShow } from '../../../selectors';
|
||||
import { BUILD_QUOTE_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { TYPOGRAPHY } from '../../../helpers/constants/design-system';
|
||||
import { BUILD_QUOTE_ROUTE } from '../../../helpers/constants/routes';
|
||||
|
||||
function getActionFunctionById(id, history) {
|
||||
const actionFunctions = {
|
||||
|
399
ui/ducks/metamask/metamask.test.js
Normal file
399
ui/ducks/metamask/metamask.test.js
Normal file
@ -0,0 +1,399 @@
|
||||
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction';
|
||||
import * as actionConstants from '../../store/actionConstants';
|
||||
import reduceMetamask, {
|
||||
getBlockGasLimit,
|
||||
getConversionRate,
|
||||
getNativeCurrency,
|
||||
getSendHexDataFeatureFlagState,
|
||||
getSendToAccounts,
|
||||
getUnapprovedTxs,
|
||||
} from './metamask';
|
||||
|
||||
describe('MetaMask Reducers', () => {
|
||||
const mockState = {
|
||||
metamask: reduceMetamask(
|
||||
{
|
||||
isInitialized: true,
|
||||
isUnlocked: true,
|
||||
featureFlags: { sendHexData: true },
|
||||
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',
|
||||
conversionRate: 1200.88200327,
|
||||
nativeCurrency: 'ETH',
|
||||
network: '3',
|
||||
provider: {
|
||||
type: 'testnet',
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
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',
|
||||
},
|
||||
},
|
||||
},
|
||||
{},
|
||||
),
|
||||
};
|
||||
it('init state', () => {
|
||||
const initState = reduceMetamask(undefined, {});
|
||||
|
||||
expect.anything(initState);
|
||||
});
|
||||
|
||||
it('locks MetaMask', () => {
|
||||
const unlockMetaMaskState = {
|
||||
isUnlocked: true,
|
||||
selectedAddress: 'test address',
|
||||
};
|
||||
const lockMetaMask = reduceMetamask(unlockMetaMaskState, {
|
||||
type: actionConstants.LOCK_METAMASK,
|
||||
});
|
||||
|
||||
expect(lockMetaMask.isUnlocked).toStrictEqual(false);
|
||||
});
|
||||
|
||||
it('sets rpc target', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SET_RPC_TARGET,
|
||||
value: 'https://custom.rpc',
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.provider.rpcUrl).toStrictEqual('https://custom.rpc');
|
||||
});
|
||||
|
||||
it('sets provider type', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SET_PROVIDER_TYPE,
|
||||
value: 'provider type',
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.provider.type).toStrictEqual('provider type');
|
||||
});
|
||||
|
||||
it('shows account detail', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SHOW_ACCOUNT_DETAIL,
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.isUnlocked).toStrictEqual(true);
|
||||
expect(state.isInitialized).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('sets account label', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SET_ACCOUNT_LABEL,
|
||||
value: {
|
||||
account: 'test account',
|
||||
label: 'test label',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.identities).toStrictEqual({
|
||||
'test account': { name: 'test label' },
|
||||
});
|
||||
});
|
||||
|
||||
it('updates tokens', () => {
|
||||
const newTokens = {
|
||||
address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4',
|
||||
decimals: 18,
|
||||
symbol: 'META',
|
||||
};
|
||||
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.UPDATE_TOKENS,
|
||||
newTokens,
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.tokens).toStrictEqual(newTokens);
|
||||
});
|
||||
|
||||
it('toggles account menu', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.TOGGLE_ACCOUNT_MENU,
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.isAccountMenuOpen).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('updates value of tx by id', () => {
|
||||
const oldState = {
|
||||
currentNetworkTxList: [
|
||||
{
|
||||
id: 1,
|
||||
txParams: 'foo',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const state = reduceMetamask(oldState, {
|
||||
type: actionConstants.UPDATE_TRANSACTION_PARAMS,
|
||||
id: 1,
|
||||
value: 'bar',
|
||||
});
|
||||
|
||||
expect(state.currentNetworkTxList[0].txParams).toStrictEqual('bar');
|
||||
});
|
||||
|
||||
it('sets blockies', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SET_USE_BLOCKIE,
|
||||
value: true,
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.useBlockie).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('updates an arbitrary feature flag', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.UPDATE_FEATURE_FLAGS,
|
||||
value: {
|
||||
foo: true,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.featureFlags.foo).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('close welcome screen', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.CLOSE_WELCOME_SCREEN,
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.welcomeScreenSeen).toStrictEqual(true);
|
||||
});
|
||||
|
||||
it('sets current locale', () => {
|
||||
const state = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SET_CURRENT_LOCALE,
|
||||
value: { locale: 'ge' },
|
||||
},
|
||||
);
|
||||
|
||||
expect(state.currentLocale).toStrictEqual('ge');
|
||||
});
|
||||
|
||||
it('sets pending tokens', () => {
|
||||
const payload = {
|
||||
address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4',
|
||||
decimals: 18,
|
||||
symbol: 'META',
|
||||
};
|
||||
|
||||
const pendingTokensState = reduceMetamask(
|
||||
{},
|
||||
{
|
||||
type: actionConstants.SET_PENDING_TOKENS,
|
||||
payload,
|
||||
},
|
||||
);
|
||||
|
||||
expect(pendingTokensState.pendingTokens).toStrictEqual(payload);
|
||||
});
|
||||
|
||||
it('clears pending tokens', () => {
|
||||
const payload = {
|
||||
address: '0x617b3f8050a0bd94b6b1da02b4384ee5b4df13f4',
|
||||
decimals: 18,
|
||||
symbol: 'META',
|
||||
};
|
||||
|
||||
const pendingTokensState = {
|
||||
pendingTokens: payload,
|
||||
};
|
||||
|
||||
const state = reduceMetamask(pendingTokensState, {
|
||||
type: actionConstants.CLEAR_PENDING_TOKENS,
|
||||
});
|
||||
|
||||
expect(state.pendingTokens).toStrictEqual({});
|
||||
});
|
||||
|
||||
describe('metamask state selectors', () => {
|
||||
describe('getBlockGasLimit', () => {
|
||||
it('should return the current block gas limit', () => {
|
||||
expect(getBlockGasLimit(mockState)).toStrictEqual('0x4c1878');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getConversionRate()', () => {
|
||||
it('should return the eth conversion rate', () => {
|
||||
expect(getConversionRate(mockState)).toStrictEqual(1200.88200327);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNativeCurrency()', () => {
|
||||
it('should return the ticker symbol of the selected network', () => {
|
||||
expect(getNativeCurrency(mockState)).toStrictEqual('ETH');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSendHexDataFeatureFlagState()', () => {
|
||||
it('should return the sendHexData feature flag state', () => {
|
||||
expect(getSendHexDataFeatureFlagState(mockState)).toStrictEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSendToAccounts()', () => {
|
||||
it('should return an array including all the users accounts and the address book', () => {
|
||||
expect(getSendToAccounts(mockState)).toStrictEqual([
|
||||
{
|
||||
code: '0x',
|
||||
balance: '0x47c9d71831c76efe',
|
||||
nonce: '0x1b',
|
||||
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',
|
||||
name: 'Send Account 1',
|
||||
},
|
||||
{
|
||||
code: '0x',
|
||||
balance: '0x37452b1315889f80',
|
||||
nonce: '0xa',
|
||||
address: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
|
||||
name: 'Send Account 2',
|
||||
},
|
||||
{
|
||||
code: '0x',
|
||||
balance: '0x30c9d71831c76efe',
|
||||
nonce: '0x1c',
|
||||
address: '0x2f8d4a878cfa04a6e60d46362f5644deab66572d',
|
||||
name: 'Send Account 3',
|
||||
},
|
||||
{
|
||||
code: '0x',
|
||||
balance: '0x0',
|
||||
nonce: '0x0',
|
||||
address: '0xd85a4b6a394794842887b8284293d69163007bbb',
|
||||
name: 'Send Account 4',
|
||||
},
|
||||
{
|
||||
address: '0x06195827297c7a80a443b6894d3bdb8824b43896',
|
||||
name: 'Address Book Account 1',
|
||||
chainId: '0x3',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the unapproved txs', () => {
|
||||
expect(getUnapprovedTxs(mockState)).toStrictEqual({
|
||||
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',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
382
ui/ducks/send/send.duck.js
Normal file
382
ui/ducks/send/send.duck.js
Normal file
@ -0,0 +1,382 @@
|
||||
import log from 'loglevel';
|
||||
import { estimateGas } from '../../store/actions';
|
||||
import { setCustomGasLimit } from '../gas/gas.duck';
|
||||
import {
|
||||
estimateGasForSend,
|
||||
calcTokenBalance,
|
||||
} from '../../pages/send/send.utils';
|
||||
|
||||
// Actions
|
||||
const OPEN_TO_DROPDOWN = 'metamask/send/OPEN_TO_DROPDOWN';
|
||||
const CLOSE_TO_DROPDOWN = 'metamask/send/CLOSE_TO_DROPDOWN';
|
||||
const UPDATE_SEND_ERRORS = 'metamask/send/UPDATE_SEND_ERRORS';
|
||||
const RESET_SEND_STATE = 'metamask/send/RESET_SEND_STATE';
|
||||
const SHOW_GAS_BUTTON_GROUP = 'metamask/send/SHOW_GAS_BUTTON_GROUP';
|
||||
const HIDE_GAS_BUTTON_GROUP = 'metamask/send/HIDE_GAS_BUTTON_GROUP';
|
||||
const UPDATE_GAS_LIMIT = 'UPDATE_GAS_LIMIT';
|
||||
const UPDATE_GAS_PRICE = 'UPDATE_GAS_PRICE';
|
||||
const UPDATE_GAS_TOTAL = 'UPDATE_GAS_TOTAL';
|
||||
const UPDATE_SEND_HEX_DATA = 'UPDATE_SEND_HEX_DATA';
|
||||
const UPDATE_SEND_TOKEN_BALANCE = 'UPDATE_SEND_TOKEN_BALANCE';
|
||||
const UPDATE_SEND_TO = 'UPDATE_SEND_TO';
|
||||
const UPDATE_SEND_AMOUNT = 'UPDATE_SEND_AMOUNT';
|
||||
const UPDATE_MAX_MODE = 'UPDATE_MAX_MODE';
|
||||
const UPDATE_SEND = 'UPDATE_SEND';
|
||||
const UPDATE_SEND_TOKEN = 'UPDATE_SEND_TOKEN';
|
||||
const CLEAR_SEND = 'CLEAR_SEND';
|
||||
const GAS_LOADING_STARTED = 'GAS_LOADING_STARTED';
|
||||
const GAS_LOADING_FINISHED = 'GAS_LOADING_FINISHED';
|
||||
const UPDATE_SEND_ENS_RESOLUTION = 'UPDATE_SEND_ENS_RESOLUTION';
|
||||
const UPDATE_SEND_ENS_RESOLUTION_ERROR = 'UPDATE_SEND_ENS_RESOLUTION_ERROR';
|
||||
|
||||
const initState = {
|
||||
toDropdownOpen: false,
|
||||
gasButtonGroupShown: true,
|
||||
errors: {},
|
||||
gasLimit: null,
|
||||
gasPrice: null,
|
||||
gasTotal: null,
|
||||
tokenBalance: '0x0',
|
||||
from: '',
|
||||
to: '',
|
||||
amount: '0',
|
||||
memo: '',
|
||||
maxModeOn: false,
|
||||
editingTransactionId: null,
|
||||
toNickname: '',
|
||||
ensResolution: null,
|
||||
ensResolutionError: '',
|
||||
gasIsLoading: false,
|
||||
};
|
||||
|
||||
// Reducer
|
||||
export default function reducer(state = initState, action) {
|
||||
switch (action.type) {
|
||||
case OPEN_TO_DROPDOWN:
|
||||
return {
|
||||
...state,
|
||||
toDropdownOpen: true,
|
||||
};
|
||||
case CLOSE_TO_DROPDOWN:
|
||||
return {
|
||||
...state,
|
||||
toDropdownOpen: false,
|
||||
};
|
||||
case UPDATE_SEND_ERRORS:
|
||||
return {
|
||||
...state,
|
||||
errors: {
|
||||
...state.errors,
|
||||
...action.value,
|
||||
},
|
||||
};
|
||||
case SHOW_GAS_BUTTON_GROUP:
|
||||
return {
|
||||
...state,
|
||||
gasButtonGroupShown: true,
|
||||
};
|
||||
case HIDE_GAS_BUTTON_GROUP:
|
||||
return {
|
||||
...state,
|
||||
gasButtonGroupShown: false,
|
||||
};
|
||||
case UPDATE_GAS_LIMIT:
|
||||
return {
|
||||
...state,
|
||||
gasLimit: action.value,
|
||||
};
|
||||
case UPDATE_GAS_PRICE:
|
||||
return {
|
||||
...state,
|
||||
gasPrice: action.value,
|
||||
};
|
||||
case RESET_SEND_STATE:
|
||||
return { ...initState };
|
||||
case UPDATE_GAS_TOTAL:
|
||||
return {
|
||||
...state,
|
||||
gasTotal: action.value,
|
||||
};
|
||||
case UPDATE_SEND_TOKEN_BALANCE:
|
||||
return {
|
||||
...state,
|
||||
tokenBalance: action.value,
|
||||
};
|
||||
case UPDATE_SEND_HEX_DATA:
|
||||
return {
|
||||
...state,
|
||||
data: action.value,
|
||||
};
|
||||
case UPDATE_SEND_TO:
|
||||
return {
|
||||
...state,
|
||||
to: action.value.to,
|
||||
toNickname: action.value.nickname,
|
||||
};
|
||||
case UPDATE_SEND_AMOUNT:
|
||||
return {
|
||||
...state,
|
||||
amount: action.value,
|
||||
};
|
||||
case UPDATE_MAX_MODE:
|
||||
return {
|
||||
...state,
|
||||
maxModeOn: action.value,
|
||||
};
|
||||
case UPDATE_SEND:
|
||||
return Object.assign(state, action.value);
|
||||
case UPDATE_SEND_TOKEN: {
|
||||
const newSend = {
|
||||
...state,
|
||||
token: action.value,
|
||||
};
|
||||
// erase token-related state when switching back to native currency
|
||||
if (newSend.editingTransactionId && !newSend.token) {
|
||||
const unapprovedTx =
|
||||
newSend?.unapprovedTxs?.[newSend.editingTransactionId] || {};
|
||||
const txParams = unapprovedTx.txParams || {};
|
||||
Object.assign(newSend, {
|
||||
tokenBalance: null,
|
||||
balance: '0',
|
||||
from: unapprovedTx.from || '',
|
||||
unapprovedTxs: {
|
||||
...newSend.unapprovedTxs,
|
||||
[newSend.editingTransactionId]: {
|
||||
...unapprovedTx,
|
||||
txParams: {
|
||||
...txParams,
|
||||
data: '',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return Object.assign(state, newSend);
|
||||
}
|
||||
case UPDATE_SEND_ENS_RESOLUTION:
|
||||
return {
|
||||
...state,
|
||||
ensResolution: action.payload,
|
||||
ensResolutionError: '',
|
||||
};
|
||||
case UPDATE_SEND_ENS_RESOLUTION_ERROR:
|
||||
return {
|
||||
...state,
|
||||
ensResolution: null,
|
||||
ensResolutionError: action.payload,
|
||||
};
|
||||
case CLEAR_SEND:
|
||||
return {
|
||||
...state,
|
||||
gasLimit: null,
|
||||
gasPrice: null,
|
||||
gasTotal: null,
|
||||
tokenBalance: null,
|
||||
from: '',
|
||||
to: '',
|
||||
amount: '0x0',
|
||||
memo: '',
|
||||
errors: {},
|
||||
maxModeOn: false,
|
||||
editingTransactionId: null,
|
||||
toNickname: '',
|
||||
};
|
||||
case GAS_LOADING_STARTED:
|
||||
return {
|
||||
...state,
|
||||
gasIsLoading: true,
|
||||
};
|
||||
|
||||
case GAS_LOADING_FINISHED:
|
||||
return {
|
||||
...state,
|
||||
gasIsLoading: false,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// Action Creators
|
||||
export function openToDropdown() {
|
||||
return { type: OPEN_TO_DROPDOWN };
|
||||
}
|
||||
|
||||
export function closeToDropdown() {
|
||||
return { type: CLOSE_TO_DROPDOWN };
|
||||
}
|
||||
|
||||
export function showGasButtonGroup() {
|
||||
return { type: SHOW_GAS_BUTTON_GROUP };
|
||||
}
|
||||
|
||||
export function hideGasButtonGroup() {
|
||||
return { type: HIDE_GAS_BUTTON_GROUP };
|
||||
}
|
||||
|
||||
export function updateSendErrors(errorObject) {
|
||||
return {
|
||||
type: UPDATE_SEND_ERRORS,
|
||||
value: errorObject,
|
||||
};
|
||||
}
|
||||
|
||||
export function resetSendState() {
|
||||
return { type: RESET_SEND_STATE };
|
||||
}
|
||||
|
||||
export function setGasLimit(gasLimit) {
|
||||
return {
|
||||
type: UPDATE_GAS_LIMIT,
|
||||
value: gasLimit,
|
||||
};
|
||||
}
|
||||
|
||||
export function setGasPrice(gasPrice) {
|
||||
return {
|
||||
type: UPDATE_GAS_PRICE,
|
||||
value: gasPrice,
|
||||
};
|
||||
}
|
||||
|
||||
export function setGasTotal(gasTotal) {
|
||||
return {
|
||||
type: UPDATE_GAS_TOTAL,
|
||||
value: gasTotal,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateGasData({
|
||||
gasPrice,
|
||||
blockGasLimit,
|
||||
selectedAddress,
|
||||
sendToken,
|
||||
to,
|
||||
value,
|
||||
data,
|
||||
}) {
|
||||
return (dispatch) => {
|
||||
dispatch(gasLoadingStarted());
|
||||
return estimateGasForSend({
|
||||
estimateGasMethod: estimateGas,
|
||||
blockGasLimit,
|
||||
selectedAddress,
|
||||
sendToken,
|
||||
to,
|
||||
value,
|
||||
estimateGasPrice: gasPrice,
|
||||
data,
|
||||
})
|
||||
.then((gas) => {
|
||||
dispatch(setGasLimit(gas));
|
||||
dispatch(setCustomGasLimit(gas));
|
||||
dispatch(updateSendErrors({ gasLoadingError: null }));
|
||||
dispatch(gasLoadingFinished());
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err);
|
||||
dispatch(updateSendErrors({ gasLoadingError: 'gasLoadingError' }));
|
||||
dispatch(gasLoadingFinished());
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function gasLoadingStarted() {
|
||||
return {
|
||||
type: GAS_LOADING_STARTED,
|
||||
};
|
||||
}
|
||||
|
||||
export function gasLoadingFinished() {
|
||||
return {
|
||||
type: GAS_LOADING_FINISHED,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendTokenBalance({ sendToken, tokenContract, address }) {
|
||||
return (dispatch) => {
|
||||
const tokenBalancePromise = tokenContract
|
||||
? tokenContract.balanceOf(address)
|
||||
: Promise.resolve();
|
||||
return tokenBalancePromise
|
||||
.then((usersToken) => {
|
||||
if (usersToken) {
|
||||
const newTokenBalance = calcTokenBalance({ sendToken, usersToken });
|
||||
dispatch(setSendTokenBalance(newTokenBalance));
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
log.error(err);
|
||||
updateSendErrors({ tokenBalance: 'tokenBalanceError' });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function setSendTokenBalance(tokenBalance) {
|
||||
return {
|
||||
type: UPDATE_SEND_TOKEN_BALANCE,
|
||||
value: tokenBalance,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendHexData(value) {
|
||||
return {
|
||||
type: UPDATE_SEND_HEX_DATA,
|
||||
value,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendTo(to, nickname = '') {
|
||||
return {
|
||||
type: UPDATE_SEND_TO,
|
||||
value: { to, nickname },
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendAmount(amount) {
|
||||
return {
|
||||
type: UPDATE_SEND_AMOUNT,
|
||||
value: amount,
|
||||
};
|
||||
}
|
||||
|
||||
export function setMaxModeTo(bool) {
|
||||
return {
|
||||
type: UPDATE_MAX_MODE,
|
||||
value: bool,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSend(newSend) {
|
||||
return {
|
||||
type: UPDATE_SEND,
|
||||
value: newSend,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendToken(token) {
|
||||
return {
|
||||
type: UPDATE_SEND_TOKEN,
|
||||
value: token,
|
||||
};
|
||||
}
|
||||
|
||||
export function clearSend() {
|
||||
return {
|
||||
type: CLEAR_SEND,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendEnsResolution(ensResolution) {
|
||||
return {
|
||||
type: UPDATE_SEND_ENS_RESOLUTION,
|
||||
payload: ensResolution,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSendEnsResolutionError(errorMessage) {
|
||||
return {
|
||||
type: UPDATE_SEND_ENS_RESOLUTION_ERROR,
|
||||
payload: errorMessage,
|
||||
};
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`IntroPopup renders the component with initial props 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="intro-popup"
|
||||
/>
|
||||
</div>
|
||||
`;
|
@ -1 +0,0 @@
|
||||
export { default } from './intro-popup';
|
@ -1,71 +0,0 @@
|
||||
.intro-popup {
|
||||
&__liquidity-sources-label {
|
||||
@include H7;
|
||||
|
||||
font-weight: bold;
|
||||
margin-bottom: 6px;
|
||||
color: $Black-100;
|
||||
|
||||
@media screen and (min-width: 576px) {
|
||||
@include H6;
|
||||
}
|
||||
}
|
||||
|
||||
&__learn-more-header {
|
||||
@include H4;
|
||||
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
&__learn-more-link {
|
||||
@include H6;
|
||||
|
||||
color: $Blue-500;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__content {
|
||||
margin-left: 24px;
|
||||
|
||||
> img {
|
||||
width: 96%;
|
||||
margin-left: -9px;
|
||||
}
|
||||
}
|
||||
|
||||
&__footer {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
&__button {
|
||||
border-radius: 100px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
&__source-logo-container {
|
||||
width: 276px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px 16px;
|
||||
background: $Grey-000;
|
||||
border-radius: 8px;
|
||||
|
||||
@media screen and (min-width: 576px) {
|
||||
width: 412px;
|
||||
|
||||
img {
|
||||
width: 364px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__popover {
|
||||
@media screen and (min-width: 576px) {
|
||||
width: 460px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
import React, { useContext } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { setSwapsFromToken } from '../../../ducks/swaps/swaps';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import { BUILD_QUOTE_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { useNewMetricEvent } from '../../../hooks/useMetricEvent';
|
||||
import { getSwapsDefaultToken } from '../../../selectors';
|
||||
import Button from '../../../components/ui/button';
|
||||
import Popover from '../../../components/ui/popover';
|
||||
|
||||
export default function IntroPopup({ onClose }) {
|
||||
const dispatch = useDispatch(useDispatch);
|
||||
const history = useHistory();
|
||||
const t = useContext(I18nContext);
|
||||
|
||||
const swapsDefaultToken = useSelector(getSwapsDefaultToken);
|
||||
const enteredSwapsEvent = useNewMetricEvent({
|
||||
event: 'Swaps Opened',
|
||||
properties: {
|
||||
source: 'Intro popup',
|
||||
active_currency: swapsDefaultToken.symbol,
|
||||
},
|
||||
category: 'swaps',
|
||||
});
|
||||
const blogPostVisitedEvent = useNewMetricEvent({
|
||||
event: 'Blog Post Visited ',
|
||||
category: 'swaps',
|
||||
});
|
||||
const contractAuditVisitedEvent = useNewMetricEvent({
|
||||
event: 'Contract Audit Visited',
|
||||
category: 'swaps',
|
||||
});
|
||||
const productOverviewDismissedEvent = useNewMetricEvent({
|
||||
event: 'Product Overview Dismissed',
|
||||
category: 'swaps',
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="intro-popup">
|
||||
<Popover
|
||||
className="intro-popup__popover"
|
||||
title={t('swapIntroPopupTitle')}
|
||||
subtitle={t('swapIntroPopupSubTitle')}
|
||||
onClose={() => {
|
||||
productOverviewDismissedEvent();
|
||||
onClose();
|
||||
}}
|
||||
footerClassName="intro-popup__footer"
|
||||
footer={
|
||||
<Button
|
||||
type="confirm"
|
||||
className="intro-popup__button"
|
||||
onClick={() => {
|
||||
onClose();
|
||||
enteredSwapsEvent();
|
||||
dispatch(setSwapsFromToken(swapsDefaultToken));
|
||||
history.push(BUILD_QUOTE_ROUTE);
|
||||
}}
|
||||
>
|
||||
{t('swapStartSwapping')}
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<div className="intro-popup__content">
|
||||
<div className="intro-popup__liquidity-sources-label">
|
||||
{t('swapIntroLiquiditySourcesLabel')}
|
||||
</div>
|
||||
<div className="intro-popup__source-logo-container">
|
||||
<img src="images/source-logos-all.svg" alt="" />
|
||||
</div>
|
||||
<div className="intro-popup__learn-more-header">
|
||||
{t('swapIntroLearnMoreHeader')}
|
||||
</div>
|
||||
<div
|
||||
className="intro-popup__learn-more-link"
|
||||
onClick={() => {
|
||||
global.platform.openTab({
|
||||
url:
|
||||
'https://medium.com/metamask/introducing-metamask-swaps-84318c643785',
|
||||
});
|
||||
blogPostVisitedEvent();
|
||||
}}
|
||||
>
|
||||
{t('swapIntroLearnMoreLink')}
|
||||
</div>
|
||||
<div
|
||||
className="intro-popup__learn-more-link"
|
||||
onClick={() => {
|
||||
global.platform.openTab({
|
||||
url:
|
||||
'https://diligence.consensys.net/audits/private/lsjipyllnw2/',
|
||||
});
|
||||
contractAuditVisitedEvent();
|
||||
}}
|
||||
>
|
||||
{t('swapLearnMoreContractsAuditReview')}
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
IntroPopup.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
};
|
@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
|
||||
import {
|
||||
renderWithProvider,
|
||||
createSwapsMockStore,
|
||||
} from '../../../../test/jest';
|
||||
import IntroPopup from '.';
|
||||
|
||||
const createProps = (customProps = {}) => {
|
||||
return {
|
||||
onClose: jest.fn(),
|
||||
...customProps,
|
||||
};
|
||||
};
|
||||
|
||||
describe('IntroPopup', () => {
|
||||
it('renders the component with initial props', () => {
|
||||
const store = configureMockStore()(createSwapsMockStore());
|
||||
const props = createProps();
|
||||
const { container } = renderWithProvider(<IntroPopup {...props} />, store);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user