Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only check network before transactions #763

Merged
merged 10 commits into from
Feb 20, 2024
33 changes: 31 additions & 2 deletions src/antelope/stores/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface LoginNativeActionData {
export interface LoginEVMActionData {
authenticator: EVMAuthenticator
network: string,
autoLogAccount?: string,
}

export interface SendActionData {
Expand Down Expand Up @@ -153,14 +154,14 @@ export const useAccountStore = defineStore(store_name, {
return success;
},

async loginEVM({ authenticator, network }: LoginEVMActionData): Promise<boolean> {
async loginEVM({ authenticator, network, autoLogAccount }: LoginEVMActionData): Promise<boolean> {
this.trace('loginEVM', network);
const label = authenticator.label;
getAntelope().events.onClear.next({ label });

let success = false;
try {
const rawAddress = await authenticator.login(network);
const rawAddress = autoLogAccount ? await authenticator.autoLogin(network, autoLogAccount) : await authenticator.login(network);
this.trace('loginEVM', 'authenticator finished with address', rawAddress);

if (rawAddress) {
Expand Down Expand Up @@ -242,6 +243,7 @@ export const useAccountStore = defineStore(store_name, {
useFeedbackStore().setLoading('account.autoLogin');
const network = localStorage.getItem('network');
const account = localStorage.getItem('account');
const rawAddress = localStorage.getItem('rawAddress');
const isNative = localStorage.getItem('isNative') === 'true';
const autoLogin = localStorage.getItem('autoLogin');
this.trace('autoLogin', account, isNative, autoLogin);
Expand All @@ -265,9 +267,11 @@ export const useAccountStore = defineStore(store_name, {
console.error(getAntelope().wallets);
throw new Error('antelope.account.error_auto_login');
}
const autoLogAccount = rawAddress ?? account;
return this.loginEVM({
authenticator,
network,
autoLogAccount,
});
}
}
Expand All @@ -293,6 +297,31 @@ export const useAccountStore = defineStore(store_name, {
}
},

async assertNetworkConnection(label: string): Promise<boolean> {
if (!await useAccountStore().isConnectedToCorrectNetwork(label)) {
return new Promise<boolean>(async (resolve) => {
const ant = getAntelope();
const authenticator = useAccountStore().loggedAccount.authenticator as EVMAuthenticator;
try {
await authenticator.ensureCorrectChain();
if (!await useAccountStore().isConnectedToCorrectNetwork(label)) {
resolve(false);
} else {
resolve(true);
}
} catch (error) {
const message = (error as Error).message;
if (message === 'antelope.evm.error_switch_chain_rejected') {
ant.config.notifyNeutralMessageHandler(message);
}
resolve(false);
}
});
} else {
return true;
}
},

async sendAction({ account, data, name, actor, permission }: SendActionData): Promise<NativeTransactionResponse> {
this.trace('sendAction', account, data, name, actor, permission);
try {
Expand Down
2 changes: 1 addition & 1 deletion src/antelope/stores/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export const useChainStore = defineStore(store_name, {
const stkToken = chain_settings.getStakedSystemToken();

const abi = [stlosAbiPreviewDeposit[0], stlosAbiPreviewRedeem[0]];
const provider = await getAntelope().wallets.getWeb3Provider();
const provider = await getAntelope().wallets.getWeb3Provider(label);
const contractInstance = new ethers.Contract(stkToken.address, abi, provider);
// Now we preview a deposit of 1 SYS to get the ratio
const oneSys = ethers.utils.parseUnits('1.0', sysToken.decimals);
Expand Down
14 changes: 7 additions & 7 deletions src/antelope/stores/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ import {

const LOCAL_SORAGE_CONTRACTS_KEY = 'antelope.contracts';

const createManager = (signer?: ethers.Signer):EvmContractManagerI => ({
const createManager = (label: string, signer?: ethers.Signer):EvmContractManagerI => ({
getSigner: async () => signer ?? null,
getWeb3Provider: () => getAntelope().wallets.getWeb3Provider(),
getWeb3Provider: () => getAntelope().wallets.getWeb3Provider(label),
getFunctionIface: (hash:string) => toRaw(useEVMStore().getFunctionIface(hash)),
getEventIface: (hash:string) => toRaw(useEVMStore().getEventIface(hash)),
});
Expand Down Expand Up @@ -187,7 +187,7 @@ export const useContractStore = defineStore(store_name, {
return this.__contracts[network].cached[addressLower];
}

const isContract = await this.addressIsContract(network, address);
const isContract = await this.addressIsContract(label, address);

if (!isContract) {
// address is an account, not a contract
Expand Down Expand Up @@ -542,7 +542,7 @@ export const useContractStore = defineStore(store_name, {
throw new AntelopeError('antelope.contracts.error_label_required');
}

const isContract = await this.addressIsContract(network, address);
const isContract = await this.addressIsContract(label, address);

if (!isContract) {
// address is an account, not a contract
Expand All @@ -561,7 +561,7 @@ export const useContractStore = defineStore(store_name, {
|| (metadata.abi ?? []).length > 0 && (metadata.abi ?? []).length > (this.__contracts[network].cached[index]?.abi?.length ?? 0)
) {
// This manager provides the signer and the web3 provider
metadata.manager = createManager(signer);
metadata.manager = createManager(label, signer);

// we create the contract using the factory
const contract = this.__factory.buildContract(metadata);
Expand All @@ -585,7 +585,8 @@ export const useContractStore = defineStore(store_name, {
this.__contracts[network].cached[index] = null;
},

async addressIsContract(network: string, address: string) {
async addressIsContract(label: string, address: string) {
const network = useChainStore().getChain(label).settings.getNetwork();
const addressLower = address.toLowerCase();

if (this.__contracts[network]?.cached[addressLower] || this.__contracts[network]?.metadata[addressLower]) {
Expand All @@ -607,7 +608,6 @@ export const useContractStore = defineStore(store_name, {
return this.__accounts[network].processing[addressLower];
}


this.__accounts[network].processing[addressLower] = new Promise(async (resolve) => {
const indexer = (useChainStore().loggedChain.settings as EVMChainSettings).getIndexer();
const isContract = (await indexer.get(`/v1/contract/${addressLower}`)).data.results.length > 0;
Expand Down
26 changes: 24 additions & 2 deletions src/antelope/wallets/authenticators/EVMAuthenticator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,28 @@ export abstract class EVMAuthenticator {
}
}

/**
* This method MUST be implemented on the derived class to perform any auto login action if needed.
* @param network network to connect to
* @param account account address being auto logged in
* @returns the account address of the user
*/
async autoLogin(network: string, account: string): Promise<addressString> {
this.trace('login', network, account);
const chain = useChainStore();
try {
chain.setChain(CURRENT_CONTEXT, network);
return account as addressString;
} catch (error) {
if ((error as unknown as ExceptionError).code === 4001) {
throw new AntelopeError('antelope.evm.error_connect_rejected');
} else {
console.error('Error:', error);
throw new AntelopeError('antelope.evm.error_login');
}
}
}

async ensureCorrectChain(): Promise<ethers.providers.Web3Provider> {
this.trace('ensureCorrectChain');
if (usePlatformStore().isMobile) {
Expand Down Expand Up @@ -110,7 +132,7 @@ export abstract class EVMAuthenticator {
async getSystemTokenBalance(address: addressString | string): Promise<ethers.BigNumber> {
this.trace('getSystemTokenBalance', address);
try {
const provider = await this.web3Provider();
const provider = await getAntelope().wallets.getWeb3Provider(this.label);
if (provider) {
return provider.getBalance(address);
} else {
Expand All @@ -132,7 +154,7 @@ export abstract class EVMAuthenticator {
async getERC20TokenBalance(address: addressString | string, token: addressString): Promise<ethers.BigNumber> {
this.trace('getERC20TokenBalance', [address, token]);
try {
const provider = await this.web3Provider();
const provider = await getAntelope().wallets.getWeb3Provider(this.label);
if (provider) {
const erc20Contract = new ethers.Contract(token, erc20Abi, provider);
const balance = await erc20Contract.balanceOf(address);
Expand Down
33 changes: 1 addition & 32 deletions src/antelope/wallets/authenticators/InjectedProviderAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { BigNumber, ethers } from 'ethers';
import { BehaviorSubject, filter, map } from 'rxjs';
import { getAntelope, useAccountStore, useChainStore, useEVMStore, useFeedbackStore } from 'src/antelope';
import { useAccountStore, useChainStore, useEVMStore, useFeedbackStore } from 'src/antelope';
import {
AntelopeError,
EthereumProvider,
Expand All @@ -27,7 +27,6 @@ export abstract class InjectedProviderAuth extends EVMAuthenticator {
async initInjectedProvider(authenticator: InjectedProviderAuth): Promise<void> {
this.trace('initInjectedProvider', authenticator.getName(), [authenticator.getProvider()]);
const provider: EthereumProvider | null = authenticator.getProvider();
const ant = getAntelope();

if (provider && !provider.__initialized) {
this.trace('initInjectedProvider', authenticator.getName(), 'initializing provider');
Expand All @@ -42,36 +41,6 @@ export abstract class InjectedProviderAuth extends EVMAuthenticator {
}
}

// this handler activates only when the user comes back from switching to the wrong network on the wallet
// It checks if the user is on the correct network and if not, it shows a notification with a button to switch
const checkNetworkHandler = async () => {
window.removeEventListener('focus', checkNetworkHandler);
if (useAccountStore().loggedAccount) {
const authenticator = useAccountStore().loggedAccount.authenticator as EVMAuthenticator;
if (await authenticator.isConnectedToCorrectChain()) {
this.trace('checkNetworkHandler', 'correct network');
} else {
const networkName = useChainStore().loggedChain.settings.getDisplay();
const errorMessage = ant.config.localizationHandler('evm_wallet.incorrect_network', { networkName });
ant.config.notifyFailureWithAction(errorMessage, {
label: ant.config.localizationHandler('evm_wallet.switch'),
handler: () => {
authenticator.ensureCorrectChain();
},
});
}
}
};

provider.on('chainChanged', (value) => {
const newNetwork = value as string;
this.trace('provider.chainChanged', newNetwork);
window.removeEventListener('focus', checkNetworkHandler);
if (useAccountStore().loggedAccount) {
window.addEventListener('focus', checkNetworkHandler);
}
});

provider.on('accountsChanged', async (value) => {
const accounts = value as string[];
const network = useChainStore().currentChain.settings.getNetwork();
Expand Down
4 changes: 4 additions & 0 deletions src/boot/antelope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,8 @@ export default boot(({ app }) => {
ant.stores.chain.setChain(CURRENT_CONTEXT, network);
}

// We can simulate the indexer being down for testing purposes by uncommenting the following line
// (ant.stores.chain.currentChain.settings as EVMChainSettings).simulateIndexerDown(true);


});
5 changes: 5 additions & 0 deletions src/boot/errorHandling.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class NotificationAction {
this.label = payload.label;
this.class = payload.class;
this.handler = payload.handler;
this.onDismiss = payload.onDismiss;
this.iconRight = payload.iconRight;
this.color = payload.color;
}
Expand Down Expand Up @@ -142,11 +143,14 @@ const notifyMessage = function(type, icon, title, message, payload, remember = '
class: 'c-notify__action-btn c-notify__action-btn--hide',
};

let onDismiss = null;

// adding buttons
if (typeof payload === 'string' && type === 'success') {
actions.push(link_btn);
} else if (typeof payload === 'object' && payload instanceof NotificationAction) {
actions.push(action_btn);
onDismiss = payload.onDismiss;
} else if (typeof payload === 'object' && type === 'error') {
actions.push(details_btn);
} else {
Expand Down Expand Up @@ -206,6 +210,7 @@ const notifyMessage = function(type, icon, title, message, payload, remember = '
html: true,
classes: 'c-notify',
actions,
onDismiss,
});
};

Expand Down
5 changes: 5 additions & 0 deletions src/pages/evm/allowances/EditAllowanceModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
isErc721SingleAllowanceRow,
} from 'src/antelope/types/Allowances';
import {
CURRENT_CONTEXT,
getAntelope,
useAccountStore,
useAllowancesStore,
Expand Down Expand Up @@ -168,6 +169,10 @@ async function handleSubmit() {
let tx: TransactionResponse;
let neutralMessageText: string;

if (!await useAccountStore().assertNetworkConnection(CURRENT_CONTEXT)) {
return;
}

if (rowIsErc20Row.value) {
tx = await useAllowancesStore().updateErc20Allowance(
userAddress.value,
Expand Down
6 changes: 5 additions & 1 deletion src/pages/evm/nfts/NftTransferForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,15 @@ onMounted(() => {
});

async function startTransfer() {
const label = CURRENT_CONTEXT;
transferLoading.value = true;
const nameString = `${props.nft.contractPrettyName || props.nft.contractAddress} #${props.nft.id}`;
try {
if (!await useAccountStore().assertNetworkConnection(label)) {
return;
}
const trx = await nftStore.transferNft(
CURRENT_CONTEXT,
label,
contractAddress,
nftId,
nftType.value,
Expand Down
9 changes: 1 addition & 8 deletions src/pages/evm/staking/StakingTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,7 @@ onBeforeMount(() => {

async function handleCtaClick() {
const label = CURRENT_CONTEXT;
if (!await accountStore.isConnectedToCorrectNetwork(label)) {
const networkName = useChainStore().loggedChain.settings.getDisplay();
const errorMessage = ant.config.localizationHandler('evm_wallet.incorrect_network', { networkName });

ant.config.notifyFailureWithAction(errorMessage, {
label: ant.config.localizationHandler('evm_wallet.switch'),
});

if (!await useAccountStore().assertNetworkConnection(label)) {
return;
}

Expand Down
9 changes: 1 addition & 8 deletions src/pages/evm/staking/UnstakingTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,7 @@ const ctaIsLoading = computed(() => ant.stores.feedback.isLoading('unstakeEVMSys

async function handleCtaClick() {
const label = CURRENT_CONTEXT;
if (!await accountStore.isConnectedToCorrectNetwork(label)) {
const networkName = useChainStore().loggedChain.settings.getDisplay();
const errorMessage = ant.config.localizationHandler('evm_wallet.incorrect_network', { networkName });

ant.config.notifyFailureWithAction(errorMessage, {
label: ant.config.localizationHandler('evm_wallet.switch'),
});

if (!await useAccountStore().assertNetworkConnection(label)) {
return;
}

Expand Down
9 changes: 1 addition & 8 deletions src/pages/evm/staking/WithdrawTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,7 @@ const handleWithdrawClick = async () => {
return;
}
const label = CURRENT_CONTEXT;
if (!accountStore.isConnectedToCorrectNetwork(label)) {
const networkName = chainStore.loggedChain.settings.getDisplay();
const errorMessage = ant.config.localizationHandler('evm_wallet.incorrect_network', { networkName });

ant.config.notifyFailureWithAction(errorMessage, {
label: ant.config.localizationHandler('evm_wallet.switch'),
});

if (!await useAccountStore().assertNetworkConnection(label)) {
return;
}

Expand Down
14 changes: 2 additions & 12 deletions src/pages/evm/wallet/SendPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -221,18 +221,8 @@ export default defineComponent({

// before sending the transaction, we check if the user is connected to the correct network
const label = CURRENT_CONTEXT;
if (!await useAccountStore().isConnectedToCorrectNetwork(label)) {
const authenticator = useAccountStore().loggedAccount.authenticator as EVMAuthenticator;
const networkName = useChainStore().loggedChain.settings.getDisplay();
const errorMessage = ant.config.localizationHandler('evm_wallet.incorrect_network', { networkName });
ant.config.notifyFailureWithAction(errorMessage, {
label: ant.config.localizationHandler('evm_wallet.switch'),
handler: async () => {
// we force the useer to manually re enter the amount which triggers updateTokenTransferConfig
this.amount = ethers.constants.Zero;
await authenticator.ensureCorrectChain();
},
});
if (!await useAccountStore().assertNetworkConnection(label)) {
this.amount = ethers.constants.Zero;
return;
}

Expand Down
Loading
Loading