Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/antelope/chains/evm/telos-evm-testnet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ const W_TOKEN = new TokenClass({

const RPC_ENDPOINT = {
protocol: 'https',
host: 'testnet.telos.net',
host: 'rpc.testnet.telos.net',
port: 443,
path: '/evm',
path: '/',
};
const ESCROW_CONTRACT_ADDRESS = '0x7E9cF9fBc881652B05BB8F26298fFAB538163b6f';
const API_ENDPOINT = 'https://api-dev.telos.net/v1';
Expand Down
4 changes: 2 additions & 2 deletions src/antelope/chains/evm/telos-evm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ const W_TOKEN = new TokenClass({

const RPC_ENDPOINT = {
protocol: 'https',
host: 'mainnet.telos.net',
host: 'rpc.telos.net',
port: 443,
path: '/evm',
path: '/',
};
const ESCROW_CONTRACT_ADDRESS = '0x95F5713A1422Aa3FBD3DCB8D553945C128ee3855';
const API_ENDPOINT = 'https://api.telos.net/v1';
Expand Down
166 changes: 94 additions & 72 deletions src/antelope/stores/allowances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
isErc20AllowanceRow,
isErc721SingleAllowanceRow,
isNftCollectionAllowanceRow,
EvmContractFactoryData,
} from 'src/antelope/types';
import { createTraceFunction } from 'src/antelope/config';
import EVMChainSettings from 'src/antelope/chains/EVMChainSettings';
Expand Down Expand Up @@ -226,94 +227,107 @@ export const useAllowancesStore = defineStore(store_name, {
// actions
async fetchAllowancesForAccount(account: string): Promise<void> {
this.trace('fetchAllowancesForAccount', account);
useFeedbackStore().setLoading('fetchAllowancesForAccount');
try {
useFeedbackStore().setLoading('fetchAllowancesForAccount');

const chainSettings = useChainStore().currentChain.settings as EVMChainSettings;
const chainSettings = useChainStore().currentChain.settings as EVMChainSettings;

if (chainSettings.isNative()) {
this.trace('fetchAllowancesForAccount', 'Native chain does not have allowances');
return;
}
if (chainSettings.isNative()) {
this.trace('fetchAllowancesForAccount', 'Native chain does not have allowances');
return;
}

const erc20AllowancesPromise = chainSettings.fetchErc20Allowances(account, { limit: ALLOWANCES_LIMIT });
const erc721AllowancesPromise = chainSettings.fetchErc721Allowances(account, { limit: ALLOWANCES_LIMIT });
const erc1155AllowancesPromise = chainSettings.fetchErc1155Allowances(account, { limit: ALLOWANCES_LIMIT });
const erc20AllowancesPromise = chainSettings.fetchErc20Allowances(account, { limit: ALLOWANCES_LIMIT });
const erc721AllowancesPromise = chainSettings.fetchErc721Allowances(account, { limit: ALLOWANCES_LIMIT });
const erc1155AllowancesPromise = chainSettings.fetchErc1155Allowances(account, { limit: ALLOWANCES_LIMIT });

let allowancesResults: IndexerAllowanceResponse[];
let allowancesResults: IndexerAllowanceResponse[];

try {
allowancesResults = await Promise.all([erc20AllowancesPromise, erc721AllowancesPromise, erc1155AllowancesPromise]);
} catch (e) {
console.error('Error fetching allowances', e);
useFeedbackStore().unsetLoading('fetchAllowancesForAccount');
throw new AntelopeError('antelope.allowances.error_fetching_allowances');
}
try {
allowancesResults = await Promise.all([erc20AllowancesPromise, erc721AllowancesPromise, erc1155AllowancesPromise]);
} catch (e) {
console.error('Error fetching allowances', e);
useFeedbackStore().unsetLoading('fetchAllowancesForAccount');
throw new AntelopeError('antelope.allowances.error_fetching_allowances');
}

const erc20AllowancesData = (allowancesResults[0] as IndexerAllowanceResponseErc20)?.results ?? [];
const erc721AllowancesData = (allowancesResults[1] as IndexerAllowanceResponseErc721)?.results ?? [];
const erc1155AllowancesData = (allowancesResults[2] as IndexerAllowanceResponseErc1155)?.results ?? [];
const erc20AllowancesData = (allowancesResults[0] as IndexerAllowanceResponseErc20)?.results ?? [];
const erc721AllowancesData = (allowancesResults[1] as IndexerAllowanceResponseErc721)?.results ?? [];
const erc1155AllowancesData = (allowancesResults[2] as IndexerAllowanceResponseErc1155)?.results ?? [];

const shapedErc20AllowanceRowPromises = Promise.allSettled(erc20AllowancesData.map(allowanceData => this.shapeErc20AllowanceRow(allowanceData)));
const shapedErc721AllowanceRowPromises = Promise.allSettled(erc721AllowancesData.map(allowanceData => this.shapeErc721AllowanceRow(allowanceData)));
const shapedErc1155AllowanceRowPromises = Promise.allSettled(erc1155AllowancesData.map(allowanceData => this.shapeErc1155AllowanceRow(allowanceData)));
// Load these in the cache so they're available later and we don't abuse the indexer API
allowancesResults.map((result) => {
for (const [address, contract] of Object.entries(result.contracts)) {
useContractStore().createAndStoreContract(CURRENT_CONTEXT, address, contract as EvmContractFactoryData);
}
});

const [settledErc20Results, settledErc721Results, settledErc1155Results] = await Promise.allSettled([
shapedErc20AllowanceRowPromises,
shapedErc721AllowanceRowPromises,
shapedErc1155AllowanceRowPromises,
]);
const shapedErc20AllowanceRowPromises = Promise.allSettled(erc20AllowancesData.map(allowanceData => this.shapeErc20AllowanceRow(allowanceData)));
const shapedErc721AllowanceRowPromises = Promise.allSettled(erc721AllowancesData.map(allowanceData => this.shapeErc721AllowanceRow(allowanceData)));
const shapedErc1155AllowanceRowPromises = Promise.allSettled(erc1155AllowancesData.map(allowanceData => this.shapeErc1155AllowanceRow(allowanceData)));

if (settledErc20Results.status === 'fulfilled') {
const shapedErc20Rows: ShapedAllowanceRowERC20[] = [];
const [settledErc20Results, settledErc721Results, settledErc1155Results] = await Promise.allSettled([
shapedErc20AllowanceRowPromises,
shapedErc721AllowanceRowPromises,
shapedErc1155AllowanceRowPromises,
]);

settledErc20Results.value.forEach((result) => {
if (result.status === 'fulfilled') {
result.value && shapedErc20Rows.push(result.value);
} else {
console.error('Error shaping ERC20 allowance row', result.reason);
}
});
if (settledErc20Results.status === 'fulfilled') {
const shapedErc20Rows: ShapedAllowanceRowERC20[] = [];

this.setErc20Allowances(CURRENT_CONTEXT, shapedErc20Rows);
} else {
console.error('Error shaping ERC20 allowance rows', settledErc20Results.reason);
}
settledErc20Results.value.forEach((result) => {
if (result.status === 'fulfilled') {
result.value && shapedErc20Rows.push(result.value);
} else {
console.error('Error shaping ERC20 allowance row', result.reason);
}
});

if (settledErc721Results.status === 'fulfilled') {
const shapedErc721Rows: (ShapedAllowanceRowSingleERC721 | ShapedAllowanceRowNftCollection)[] = [];
this.setErc20Allowances(CURRENT_CONTEXT, shapedErc20Rows);
} else {
console.error('Error shaping ERC20 allowance rows', settledErc20Results.reason);
}

settledErc721Results.value.forEach((result) => {
if (result.status === 'fulfilled') {
result.value && shapedErc721Rows.push(result.value);
} else {
console.error('Error shaping ERC721 allowance row', result.reason);
}
});
if (settledErc721Results.status === 'fulfilled') {
const shapedErc721Rows: (ShapedAllowanceRowSingleERC721 | ShapedAllowanceRowNftCollection)[] = [];

this.setErc721Allowances(CURRENT_CONTEXT, shapedErc721Rows);
} else {
console.error('Error shaping ERC721 allowance rows', settledErc721Results.reason);
}
settledErc721Results.value.forEach((result) => {
if (result.status === 'fulfilled') {
result.value && shapedErc721Rows.push(result.value);
} else {
console.error('Error shaping ERC721 allowance row', result.reason);
}
});

if (settledErc1155Results.status === 'fulfilled') {
const shapedErc1155Rows: ShapedAllowanceRowNftCollection[] = [];
this.setErc721Allowances(CURRENT_CONTEXT, shapedErc721Rows);
} else {
console.error('Error shaping ERC721 allowance rows', settledErc721Results.reason);
}

settledErc1155Results.value.forEach((result) => {
if (result.status === 'fulfilled') {
result.value && shapedErc1155Rows.push(result.value);
} else {
console.error('Error shaping ERC1155 allowance row', result.reason);
}
});
if (settledErc1155Results.status === 'fulfilled') {
const shapedErc1155Rows: ShapedAllowanceRowNftCollection[] = [];

this.setErc1155Allowances(CURRENT_CONTEXT, shapedErc1155Rows);
} else {
console.error('Error shaping ERC1155 allowance rows', settledErc1155Results.reason);
}
settledErc1155Results.value.forEach((result) => {
if (result.status === 'fulfilled') {
result.value && shapedErc1155Rows.push(result.value);
} else {
console.error('Error shaping ERC1155 allowance row', result.reason);
}
});

this.setErc1155Allowances(CURRENT_CONTEXT, shapedErc1155Rows);
} else {
console.error('Error shaping ERC1155 allowance rows', settledErc1155Results.reason);
}

useFeedbackStore().unsetLoading('fetchAllowancesForAccount');
useFeedbackStore().unsetLoading('fetchAllowancesForAccount');

return Promise.resolve();
return Promise.resolve();
} catch (e) {
useFeedbackStore().unsetLoading('fetchAllowancesForAccount');
console.error('Error fetching allowances', e);
throw new AntelopeError('antelope.allowances.error_fetching_allowances');
}
},
async updateErc20Allowance(
owner: string,
Expand Down Expand Up @@ -544,6 +558,16 @@ export const useAllowancesStore = defineStore(store_name, {
this.__erc_721_allowances[label] = [];
this.__erc_1155_allowances[label] = [];
},
async fetchBalanceString(data: IndexerErc20AllowanceResult): Promise<string> {
const indexer = (useChainStore().loggedChain.settings as EVMChainSettings).getIndexer();
const results = (await indexer.get(`/v1/token/${data.contract}/holders?account=${data.owner}`)).data.results;
if (results.length === 0) {
return '0';
} else {
const balanceString = results[0].balance;
return balanceString;
}
},
async shapeErc20AllowanceRow(data: IndexerErc20AllowanceResult): Promise<ShapedAllowanceRowERC20 | null> {
try {
const spenderContract = await useContractStore().getContract(CURRENT_CONTEXT, data.spender);
Expand All @@ -559,9 +583,7 @@ export const useAllowancesStore = defineStore(store_name, {
)?.amount;

if (!balance) {
const indexer = (useChainStore().loggedChain.settings as EVMChainSettings).getIndexer();
const balanceString = (await indexer.get(`/v1/token/${data.contract}/holders?account=${data.owner}`)).data.results[0].balance;

const balanceString = await this.fetchBalanceString(data);
balance = BigNumber.from(balanceString);
}

Expand Down
23 changes: 19 additions & 4 deletions src/antelope/stores/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,24 @@ export const useContractStore = defineStore(store_name, {
this.__contracts[network].cached[index] = null;
},

async fetchIsContract(addressLower: string): Promise<boolean> {
// We use a try/catch in case the request returns a 404 or similar
try {
const indexer = (useChainStore().loggedChain.settings as EVMChainSettings).getIndexer();
const response = await indexer.get('/v1/contract/' + addressLower);

// If we have a valid data.results array and it has at least one element, return true
if (response.data?.results?.length > 0) {
return true;
} else {
return false;
}
} catch (error) {
// If an error is thrown (e.g. 404), we assume it's not a contract
return false;
}
},

async addressIsContract(label: string, address: string) {
const network = useChainStore().getChain(label).settings.getNetwork();
const addressLower = address.toLowerCase();
Expand All @@ -609,13 +627,10 @@ export const useContractStore = defineStore(store_name, {
}

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;

const isContract = await this.fetchIsContract(addressLower);
if (!isContract && !this.__accounts[network].addresses.includes(addressLower)) {
this.__accounts[network].addresses.push(addressLower);
}

resolve(isContract);
});

Expand Down
1 change: 0 additions & 1 deletion src/boot/antelope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ export default boot(({ app }) => {
next: async () => {
// first recreate the authenticators based on the new network
const zeroAuthenticators = app.config.globalProperties.recreateAuthenticator();
console.log('zeroAuthenticators', zeroAuthenticators);
// set the new authenticators list
ant.config.setAuthenticatorsGetter(() => zeroAuthenticators);
for (const authenticator of zeroAuthenticators) {
Expand Down
3 changes: 0 additions & 3 deletions src/boot/ual.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,9 @@ export default boot(async ({ app, store }) => {


app.config.globalProperties.recreateAuthenticator = function() {
console.log('UAL.recreateAuthenticator()');

if (useChainStore().currentChain.settings.isNative()) {
const settings = useChainStore().currentNativeChain.settings;
console.log('UAL.recreateAuthenticator()', { settings });

const ual_chain = {
chainId: settings.getChainId(),
Expand All @@ -164,7 +162,6 @@ export default boot(async ({ app, store }) => {

return authenticators;
} else {
console.log('UAL.recreateAuthenticator() - not native chain');
return [];
}
};
Expand Down
1 change: 1 addition & 0 deletions src/i18n/en-us/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ export default {
aside_content_fragment_4_bold: 'approvals ',
aside_content_fragment_5: 'enable app functionality and enhance your user experience. However, it\'s prudent to review and manage these permissions to deter unauthorized transactions, adding a layer of security to your wallet.',
revoke_selected: 'Revoke selected',
refresh: 'Refresh',
search_label: 'Filter by token, allowance, spender, or contract address',
includes_cancelled_allowances: 'Includes cancelled allowances',
excludes_cancelled_allowances: 'Does not include cancelled allowances',
Expand Down
22 changes: 11 additions & 11 deletions src/pages/evm/allowances/AllowancesPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,21 @@ const shapedAllowanceRows = computed(() => {

const enableRevokeButton = computed(() => selectedRows.value.length > 0);

const updateAllowances = () => {
loading.value = true;
return useAllowancesStore().fetchAllowancesForAccount(userAddress.value).then(() => {
loading.value = false;
});
};

// watchers
watch(userAddress, (address) => {
if (address) {
loading.value = true;
useAllowancesStore().fetchAllowancesForAccount(address).then(() => {
loading.value = false;
});
updateAllowances();
}

}, { immediate: true });

// methods
onMounted(() => {
timeout.value = setTimeout(() => {
useAllowancesStore().fetchAllowancesForAccount(userAddress.value);
}, 13000);
});

onBeforeUnmount(() => {
if (timeout.value) {
Expand Down Expand Up @@ -230,7 +228,7 @@ function handleRevokeSelectedClicked() {
cancelBatchRevokeButtonLoading.value = true;

setTimeout(() => {
useAllowancesStore().fetchAllowancesForAccount(userAddress.value).finally(() => {
updateAllowances().finally(() => {
cancelBatchRevokeButtonLoading.value = false;
showRevokeInProgressModal.value = false;

Expand Down Expand Up @@ -264,9 +262,11 @@ function handleRevokeSelectedClicked() {
<AllowancesPageControls
v-if="!showEmptyState"
:enable-revoke-button="enableRevokeButton"
:loading="loading"
@search-updated="handleSearchUpdated"
@include-cancelled-updated="handleIncludeCancelledUpdated"
@revoke-selected="handleRevokeSelectedClicked"
@refresh="updateAllowances"
/>

<div v-if="loading" class="q-mt-lg">
Expand Down
Loading
Loading