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

v2.3.2-rc #693

Merged
merged 20 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
806bce0
solving conflicts
Viterbo Oct 19, 2023
a9a612b
Merge branch '626-refactor-walletconnectauth-using-signcustomtransact…
Viterbo Oct 19, 2023
a5b03ca
now all Authenticators handle cancel correctly
Viterbo Nov 16, 2023
349bd3a
forgot to add support for WalletConnectAuth
Viterbo Nov 16, 2023
c19eac1
Update balances.ts
donnyquixotic Nov 16, 2023
c5b81c9
adding support for both cancel buttons
Viterbo Nov 18, 2023
449e178
fixing cancel on WalletConnect mobile or desktop+QR
Viterbo Nov 20, 2023
f918369
adding Brave Wallet support for auth
Viterbo Nov 21, 2023
e29e432
removed the loalStorage.clear() that was called in all sessions
Viterbo Nov 23, 2023
20d8102
avoiding local storage gets cleared every session
Viterbo Nov 25, 2023
b3cd8d3
warn about telos cloud and shedule login button 2 B removed
Viterbo Nov 23, 2023
f338f8e
warn about telos cloud and shedule login button 2 B removed
Viterbo Nov 23, 2023
a187f4f
making the whole checkbox text clickable
Viterbo Nov 27, 2023
6eb6358
adding docs and more fixes on the supportedInterfaces property
Viterbo Nov 20, 2023
9d16f2e
chore: bump version
donnyquixotic Nov 28, 2023
3751139
Merge pull request #683 from telosnetwork/644-create-new-evmauthentic…
donnyquixotic Nov 28, 2023
0e1fecc
fixing the case when the injected provider does not have an account
Viterbo Nov 28, 2023
f15c4ad
Update WalletConnectAuth.ts
ezra-sg Nov 28, 2023
a5b88ac
fix ipfs too many calls, update gateway
ezra-sg Nov 28, 2023
3569889
Merge branch 'master' into develop
donnyquixotic Nov 28, 2023
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "telos-web-wallet",
"version": "2.3.2",
"version": "2.3.3",
"description": "A Web Wallet for Telos",
"productName": "Telos Web Wallet",
"private": true,
Expand Down
74 changes: 48 additions & 26 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@
<script lang="ts">
import { useChainStore } from 'src/antelope';
import { getAntelope, useChainStore } from 'src/antelope';
import { ComplexMessage } from 'src/antelope/config';
import EVMChainSettings from 'src/antelope/chains/EVMChainSettings';
import { TELOS_CHAIN_IDS } from 'src/antelope/chains/chain-constants';
import packageInfo from '../package.json';
import { defineComponent } from 'vue';

export default {
export const isTodayBeforeTelosCloudDown = new Date().getTime() < new Date('2023-12-31').getTime();

export default defineComponent({
name: 'App',
created() {
const appVersionJustUpdated = 'UPDATED_NOTIFY_USER';
const userIsNew = !localStorage.getItem('account');
const currentVersion = packageInfo.version;
const clientVersion = localStorage.getItem('appVersion');

console.info('Wallet version: ', packageInfo.version);

if (clientVersion && clientVersion !== appVersionJustUpdated) {
console.info('Client version: ', clientVersion);
}
if (clientVersion !== currentVersion) {
if (clientVersion && clientVersion !== appVersionJustUpdated) {
console.info('Client version: ', clientVersion);
}

// when localstorage is cleared, we need to reload the page for it to take effect.
// however if we immediately reload the page here we cannot show a notification to the user.
// so the const appVersionUpdated lets us know after the reload that we just cleared the old localStorage
// and need to notify the user that they need to log in again
if (clientVersion === appVersionJustUpdated) {
console.info('App version mismatch, local storage cleared');
// App version was updated, localStorage was cleared, and the page reloaded
// Now inform the user that the app was updated & have them login again, and set the client app version
localStorage.setItem('appVersion', currentVersion);
(this as any).$notifySuccessMessage(
(this as any).$t('global.new_app_version'),
);
} else if (userIsNew) {
localStorage.clear();
localStorage.setItem('appVersion', currentVersion);
} else if (clientVersion !== currentVersion) {
localStorage.clear();
localStorage.setItem('appVersion', appVersionJustUpdated);
window.location.reload();
// when localstorage is cleared, we need to reload the page for it to take effect.
// however if we immediately reload the page here we cannot show a notification to the user.
// so the const appVersionUpdated lets us know after the reload that we just cleared the old localStorage
// and need to notify the user that they need to log in again
if (clientVersion === appVersionJustUpdated) {
console.info('App version mismatch, local storage cleared');
// App version was updated, localStorage was cleared, and the page reloaded
// Now inform the user that the app was updated & have them login again, and set the client app version
localStorage.setItem('appVersion', currentVersion);
(this as any).$notifySuccessMessage(
(this as any).$t('global.new_app_version'),
);
} else if (userIsNew) {
localStorage.clear();
localStorage.setItem('appVersion', currentVersion);
} else {
localStorage.clear();
localStorage.setItem('appVersion', appVersionJustUpdated);
window.location.reload();
}
}
},
mounted() {
Expand All @@ -51,8 +56,25 @@ export default {
script.defer = true;
document.body.appendChild(script);
}

if (isTodayBeforeTelosCloudDown) {
getAntelope().config.notifyRememberInfoHandler(
this.$t('temporal.telos_cloud_discontinued_title'),
[{
tag: 'p',
class: 'c-notify__message--subtitle',
text: this.$t('temporal.telos_cloud_discontinued_message_title'),
}, {
tag: 'p',
class: '',
text: this.$t('temporal.telos_cloud_discontinued_message_body'),
}],
'',
'telos-cloud-discontinued',
);
}
},
};
});
</script>

<template>
Expand Down
6 changes: 6 additions & 0 deletions src/antelope/chains/EVMChainSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,12 @@ export default abstract class EVMChainSettings implements ChainSettings {
supply: nftResponse.supply,
}));

// we fix the supportedInterfaces property if it is undefined in the response but present in the request
Object.values(response.contracts).forEach((contract) => {
contract.supportedInterfaces = contract.supportedInterfaces ||
params.type ? [params.type?.toLowerCase() as string] : undefined;
});

this.processNftContractsCalldata(response.contracts);
const shapedNftData = this.shapeNftRawData(shapedIndexerNftData, response.contracts);
return this.processNftRawData(shapedNftData);
Expand Down
20 changes: 20 additions & 0 deletions src/antelope/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import { App } from 'vue';
import { getAntelope } from 'src/antelope';
import { AntelopeError, AntelopeErrorPayload } from 'src/antelope/types';

export interface ComplexMessage {
tag: string,
class: string,
text: string,
}

export class AntelopeConfig {
transactionError(description: string, error: unknown): AntelopeError {
if (error instanceof AntelopeError) {
Expand Down Expand Up @@ -36,6 +42,7 @@ export class AntelopeConfig {
private __notify_failure_action_handler: (message: string, payload?: AntelopeErrorPayload) => void = alert;
private __notify_disconnected_handler: () => void = alert;
private __notify_neutral_message_handler: (message: string) => (() => void) = () => (() => void 0);
private __notify_remember_info_handler: (title: string, message: string | ComplexMessage[], payload: string, key: string) => (() => void) = () => (() => void 0);

// ual authenticators list getter --
private __authenticators_getter: () => Authenticator[] = () => [];
Expand Down Expand Up @@ -159,6 +166,10 @@ export class AntelopeConfig {
return this.__notify_neutral_message_handler;
}

get notifyRememberInfoHandler() {
return this.__notify_remember_info_handler;
}

get authenticatorsGetter() {
return this.__authenticators_getter;
}
Expand Down Expand Up @@ -225,6 +236,15 @@ export class AntelopeConfig {
this.__notify_neutral_message_handler = handler;
}

public setNotifyRememberInfoHandler(handler: (
title: string,
message: string | ComplexMessage[],
payload: string,
key: string,
) => (() => void)) {
this.__notify_remember_info_handler = handler;
}

// setting authenticators getter --
public setAuthenticatorsGetter(getter: () => Authenticator[]) {
this.__authenticators_getter = getter;
Expand Down
11 changes: 9 additions & 2 deletions src/antelope/stores/balances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,20 +307,27 @@ export const useBalancesStore = defineStore(store_name, {
const funcname = 'transferTokens';
this.trace(funcname, token, to, amount.toString(), memo);
const label = CURRENT_CONTEXT;
let promise = Promise.resolve({} as TransactionResponse);
try {
useFeedbackStore().setLoading(funcname);
const chain = useChainStore().loggedChain;
if (chain.settings.isNative()) {
const chain_settings = chain.settings as NativeChainSettings;
const account = useAccountStore().loggedAccount;
return await this.transferNativeTokens(chain_settings, account, token, to, amount, memo ?? '')
promise = this.transferNativeTokens(chain_settings, account, token, to, amount, memo ?? '')
.then(r => this.subscribeForTransactionReceipt(account, r));
} else {
const chain_settings = chain.settings as EVMChainSettings;
const account = useAccountStore().loggedAccount as EvmAccountModel;
return this.transferEVMTokens(label, chain_settings, account, token, to, amount)
promise = this.transferEVMTokens(label, chain_settings, account, token, to, amount)
.then(r => this.subscribeForTransactionReceipt(account, r as TransactionResponse));
}
promise.catch((error) => {
const trxError = getAntelope().config.transactionError('antelope.evm.error_transfer_failed', error);
getAntelope().config.transactionErrorHandler(trxError, funcname);
throw trxError;
});
return promise;
} catch (error) {
const trxError = getAntelope().config.transactionError('antelope.evm.error_transfer_failed', error);
getAntelope().config.transactionErrorHandler(trxError, funcname);
Expand Down
71 changes: 66 additions & 5 deletions src/antelope/stores/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,16 @@ export const useContractStore = defineStore(store_name, {
return resolve(this.createAndStoreVerifiedContract(label, addressLower, metadata, creationInfo, suspectedToken));
}

const contract = await this.createAndStoreContractFromTokenList(label, address, suspectedToken, creationInfo);
if (contract) {
this.trace('fetchContractUsingHyperion', 'returning contract from token list', address, contract);
return resolve(contract);
const tokenContract = await this.createAndStoreContractFromTokenList(label, address, suspectedToken, creationInfo);
if (tokenContract) {
this.trace('fetchContractUsingHyperion', 'returning contract from token list', address, tokenContract);
return resolve(tokenContract);
}

const suspectedTokenContract = await this.createAndStoreContractFromSuspectedType(label, address, suspectedToken, creationInfo);
if (suspectedTokenContract) {
this.trace('fetchContractUsingHyperion', 'returning contract from suspected type', address, suspectedTokenContract);
return resolve(suspectedTokenContract);
}

if (creationInfo) {
Expand Down Expand Up @@ -395,6 +401,16 @@ export const useContractStore = defineStore(store_name, {
},

// utility functions ---------------------
/**
* This function creates a verified contract based on its metadata and creation info,
* which was used to verify this contract previously.
* @param label identifies the chain
* @param address address of the contract
* @param metadata verified metadata of the contract
* @param creationInfo creation info of the contract
* @param suspectedType type of the contract. It can be 'erc20', 'erc721' or 'erc1155'
* @returns the contract
*/
async createAndStoreVerifiedContract(
label: string,
address:string,
Expand All @@ -415,6 +431,13 @@ export const useContractStore = defineStore(store_name, {
} as EvmContractFactoryData);
},

/**
* This function creates an empty contract based on its creation info.
* @param label identifies the chain
* @param address address of the contract
* @param creationInfo creation info of the contract
* @returns the contract
*/
async createAndStoreEmptyContract(
label: string,
address:string,
Expand All @@ -425,10 +448,19 @@ export const useContractStore = defineStore(store_name, {
name: `0x${address.slice(0, 16)}...`,
address,
creationInfo,
supportedInterfaces: [],
supportedInterfaces: undefined,
} as EvmContractFactoryData);
},

/**
* This function tries to create a contract based on the known token list.
* If the address is not in the list, it will return null.
* @param label identifies the chain
* @param address address of the contract
* @param suspectedType type of the contract. It can be 'erc20', 'erc721' or 'erc1155'
* @param creationInfo creation info of the contract
* @returns the contract or null if the address is not in the token list
*/
async createAndStoreContractFromTokenList(
label:string,
address:string,
Expand All @@ -451,6 +483,35 @@ export const useContractStore = defineStore(store_name, {
}
},

/**
* This function tries to create a contract from a suspected type (using the corresponding known ABI).
* It will return null if the type is not supported.
* @param label identifies the chain
* @param address address of the contract
* @param suspectedType type of the contract. It can be 'erc20', 'erc721' or 'erc1155'
* @param creationInfo creation info of the contract
* @returns the contract or null if the type is not supported
*/
async createAndStoreContractFromSuspectedType(
label:string,
address:string,
suspectedType:string,
creationInfo:EvmContractCreationInfo | null,
): Promise<EvmContract | null> {
const abi = this.getTokenABI(suspectedType);
if (abi) {
return this.createAndStoreContract(label, address, {
name: `0x${address.slice(0, 16)}...`,
address,
creationInfo,
abi,
supportedInterfaces: [suspectedType],
} as EvmContractFactoryData);
} else {
return null;
}
},

// commits -----
createAndStoreContract(label: string, address: string, metadata: EvmContractFactoryData): EvmContract {
const network = useChainStore().getChain(label).settings.getNetwork();
Expand Down
1 change: 1 addition & 0 deletions src/antelope/stores/nfts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ export const useNftsStore = defineStore(store_name, {
const new_filter = {
...toRaw(this.__pagination_filter),
tokenId,
type,
};

// If we already have a contract for that network and contract, we search for the NFT in that list first
Expand Down
6 changes: 4 additions & 2 deletions src/antelope/stores/utils/nft-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { IndexerNftMetadata, NFTSourceTypes, NftSourceType } from 'src/antelope/types';
import { urlIsAudio, urlIsPicture, urlIsVideo } from 'src/antelope/stores/utils/media-utils';

export const IPFS_GATEWAY = 'https://cloudflare-ipfs.com/ipfs/';
export const IPFS_GATEWAY = 'https://ipfs.telos.net/ipfs/';

/**
* Given an imageCache URL, tokenUri, and metadata, extract the image URL, mediaType, and mediaSource
Expand Down Expand Up @@ -109,7 +109,9 @@ export async function extractNftMetadata(
}
}

if (metadata?.image?.includes(IPFS_GATEWAY)) {
const metadataImageIsMediaUrl = await urlIsVideo(metadata?.image ?? '') || await urlIsAudio(metadata?.image ?? '') || urlIsPicture(metadata?.image ?? '');

if (metadata?.image?.includes(IPFS_GATEWAY) && !metadataImageIsMediaUrl) {
mediaType = await determineIpfsMediaType(metadata?.image);

if (mediaType === NFTSourceTypes.IMAGE) {
Expand Down
1 change: 1 addition & 0 deletions src/antelope/types/Filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,5 @@ export interface IndexerCollectionNftsFilter extends IndexerPaginationFilter {
includeAbi?: boolean; // indicate whether to include abi
tokenId?: string; // only query results for a specific token ID
includeTokenIdSupply?: boolean;
type?: NftTokenInterface;
}
23 changes: 18 additions & 5 deletions src/antelope/wallets/authenticators/OreIdAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,17 @@ export class OreIdAuth extends EVMAuthenticator {
return this.userChainAccount?.chainAccount as addressString;
}

handleCatchError(error: never): AntelopeError {
this.trace('handleCatchError', error);
console.error(error);
return new AntelopeError('antelope.evm.error_send_transaction', { error });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
handleCatchError(error: Error): AntelopeError {
this.trace('handleCatchError', error.message);
if (
error.message === 'Closed by user' ||
error.message === 'sign_transaction_cancelled_by_user'
) {
return new AntelopeError('antelope.evm.error_transaction_canceled');
} else {
return new AntelopeError('antelope.evm.error_send_transaction', { error });
}
}

/**
Expand All @@ -226,7 +233,7 @@ export class OreIdAuth extends EVMAuthenticator {
}

async performOreIdTransaction(from: addressString, json: JSONObject): Promise<EvmTransactionResponse> {

this.trace('performOreIdTransaction', from, json);
const oreIdInstance = oreId as OreId;

// sign a blockchain transaction
Expand All @@ -253,10 +260,16 @@ export class OreIdAuth extends EVMAuthenticator {
this.trace('sendSystemToken', to, amount.toString());
const from = this.getAccountAddress();
const value = amount.toHexString();

// Send the transaction
return this.performOreIdTransaction(from, {
from,
to,
value,
}).then(
(transaction: ethers.providers.TransactionResponse) => transaction,
).catch((error) => {
throw this.handleCatchError(error);
});
}

Expand Down
Loading
Loading