Skip to content

Commit

Permalink
Tm/feature/sign steps (#54)
Browse files Browse the repository at this point in the history
Update sign steps
  • Loading branch information
arhtudormorar authored Dec 23, 2024
1 parent 31c6ed4 commit 079d116
Show file tree
Hide file tree
Showing 38 changed files with 1,382 additions and 146 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
},
"peerDependencies": {
"@multiversx/sdk-core": ">= 13.5.0",
"@multiversx/sdk-dapp-utils": ">= 1.0.0",
"@multiversx/sdk-dapp-utils": ">= 1.0.2",
"@multiversx/sdk-web-wallet-cross-window-provider": ">= 2.0.4",
"axios": ">=1.6.5",
"bignumber.js": "9.x",
Expand All @@ -65,7 +65,7 @@
"devDependencies": {
"@eslint/js": "9.15.0",
"@multiversx/sdk-core": ">= 13.5.0",
"@multiversx/sdk-dapp-utils": "1.0.0",
"@multiversx/sdk-dapp-utils": ">= 1.0.2",
"@multiversx/sdk-web-wallet-cross-window-provider": ">= 2.0.4",
"@swc/core": "^1.4.17",
"@swc/jest": "^0.2.36",
Expand Down
4 changes: 3 additions & 1 deletion src/apiCalls/account/getAccountFromApi.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { ACCOUNTS_ENDPOINT } from 'apiCalls/endpoints';
import { axiosInstance } from 'apiCalls/utils/axiosInstance';
import { getCleanApiAddress } from 'apiCalls/utils/getCleanApiAddress';
import { TIMEOUT } from 'constants/network.constants';
import { AccountType } from 'types/account.types';

export const accountFetcher = (address: string | null) => {
const apiAddress = getCleanApiAddress();
const url = `${apiAddress}/${ACCOUNTS_ENDPOINT}/${address}?withGuardianInfo=true`;
// we need to get it with an axios instance because of cross-window user interaction issues
return axiosInstance.get(url, {
baseURL: apiAddress
baseURL: apiAddress,
timeout: TIMEOUT
});
};

Expand Down
18 changes: 18 additions & 0 deletions src/apiCalls/account/getScamAddressData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import axios from 'axios';
import { getCleanApiAddress } from 'apiCalls/utils';
import { TIMEOUT } from 'constants/index';
import { ScamInfoType } from 'types/account.types';
import { ACCOUNTS_ENDPOINT } from '../endpoints';

export async function getScamAddressData(addressToVerify: string) {
const apiAddress = getCleanApiAddress();

const { data } = await axios.get<{
scamInfo?: ScamInfoType;
code?: string;
}>(`${apiAddress}/${ACCOUNTS_ENDPOINT}/${addressToVerify}`, {
timeout: TIMEOUT
});

return data;
}
21 changes: 20 additions & 1 deletion src/apiCalls/configuration/getServerConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@ export async function getServerConfiguration(apiAddress: string) {

try {
const { data } = await axios.get<NetworkType>(configUrl);
return data;
if (data != null) {
// TODO: egldDenomination will be removed from API when dapp-core v1 will be discontinued
const egldDenomination = 'egldDenomination';
if (egldDenomination in data) {
const {
[egldDenomination]: decimals,
decimals: digits,
...rest
} = data as NetworkType & {
[egldDenomination]: string;
};
const networkConfig: NetworkType = {
...rest,
decimals,
digits
};
return networkConfig;
}
return data;
}
} catch (_err) {
console.error('error fetching configuration for ', configUrl);
}
Expand Down
25 changes: 25 additions & 0 deletions src/apiCalls/economics/getEconomics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from 'axios';
import { ECONOMICS_ENDPOINT } from 'apiCalls/endpoints';
import { getCleanApiAddress } from 'apiCalls/utils/getCleanApiAddress';

export interface EconomicsInfoType {
totalSupply: number;
circulatingSupply: number;
staked: number;
price: number;
marketCap: number;
apr: number;
topUpApr: number;
}

export async function getEconomics(url = ECONOMICS_ENDPOINT) {
const apiAddress = getCleanApiAddress();
const configUrl = `${apiAddress}/${url}`;
try {
const { data } = await axios.get<EconomicsInfoType>(configUrl);
return data;
} catch (err) {
console.error('err fetching economics info', err);
return null;
}
}
25 changes: 25 additions & 0 deletions src/apiCalls/tokens/getPersistedToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { getCleanApiAddress } from 'apiCalls/utils';
import { axiosInstance } from 'apiCalls/utils/axiosInstance';
import { TIMEOUT } from 'constants/network.constants';
import { tokenDataStorage } from './tokenDataStorage';

export async function getPersistedToken<T>(url: string): Promise<T> {
const apiAddress = getCleanApiAddress();

const config = {
baseURL: apiAddress,
timeout: TIMEOUT
};

const cachedToken: T | null = await tokenDataStorage.getItem(url);

if (cachedToken) {
return cachedToken;
}

const response = await axiosInstance.get<T>(url, config);

await tokenDataStorage.setItem(url, response.data);

return response.data;
}
104 changes: 104 additions & 0 deletions src/apiCalls/tokens/getPersistedTokenDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { NFTS_ENDPOINT, TOKENS_ENDPOINT } from 'apiCalls/endpoints';
import { getPersistedToken } from 'apiCalls/tokens/getPersistedToken';
import { networkSelector } from 'store/selectors/networkSelectors';
import { getState } from 'store/store';

import { NftEnumType } from 'types/tokens.types';
import { getIdentifierType } from 'utils/validation/getIdentifierType';

export interface TokenAssets {
description: string;
status: string;
svgUrl: string;
website?: string;
pngUrl?: string;
social?: any;
extraTokens?: string[];
lockedAccounts?: { [key: string]: string };
}

export interface TokenMediaType {
url?: string;
originalUrl?: string;
thumbnailUrl?: string;
fileType?: string;
fileSize?: number;
}

export interface TokenOptionType {
tokenLabel: string;
tokenDecimals: number;
tokenImageUrl: string;
assets?: TokenAssets;
type?: NftEnumType;
error?: string;
esdtPrice?: number;
ticker?: string;
identifier?: string;
name?: string;
}

interface TokenInfoResponse {
identifier: string;
name: string;
ticker: string;
decimals: number;
type?: NftEnumType;
assets: TokenAssets;
media?: TokenMediaType[];
price: number;
}

export async function getPersistedTokenDetails({
tokenId
}: {
tokenId?: string;
}): Promise<TokenOptionType> {
const network = networkSelector(getState());

const noData = {
tokenDecimals: Number(network.decimals),
tokenLabel: '',
tokenImageUrl: ''
};

const { isNft } = getIdentifierType(tokenId);

const tokenIdentifier = tokenId;
const tokenEndpoint = isNft ? NFTS_ENDPOINT : TOKENS_ENDPOINT;

if (!tokenIdentifier) {
return noData;
}

try {
const selectedToken = await getPersistedToken<TokenInfoResponse>(
`${network.apiAddress}/${tokenEndpoint}/${tokenIdentifier}`
);

const tokenDecimals = selectedToken
? selectedToken?.decimals
: Number(network.decimals);
const tokenLabel = selectedToken ? selectedToken?.name : '';
const tokenImageUrl = selectedToken
? selectedToken?.assets?.svgUrl ?? selectedToken?.media?.[0]?.thumbnailUrl
: '';

return {
tokenDecimals: tokenDecimals,
tokenLabel,
type: selectedToken?.type,
tokenImageUrl,
identifier: selectedToken?.identifier,
assets: selectedToken?.assets,
esdtPrice: selectedToken?.price,
ticker: selectedToken?.ticker,
name: selectedToken?.name
};
} catch (error) {
return {
...noData,
error: `${error}`
};
}
}
33 changes: 33 additions & 0 deletions src/apiCalls/tokens/tokenDataStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
let memoryCache: Record<string, string> = {};

export let tokenDataStorage = {
setItem: async <T>(key: string, tokenData: T) => {
try {
memoryCache[key] = JSON.stringify(tokenData);
} catch (e) {
console.error('tokenDataStorage unable to serialize', e);
}
},
getItem: async (key: string) => {
if (!memoryCache[key]) {
return null;
}
try {
return JSON.parse(memoryCache[key]);
} catch (e) {
console.error('tokenDataStorage unable to parse', e);
}
},
clear: async () => {
memoryCache = {};
},
removeItem: async (key: string) => {
delete memoryCache[key];
}
};

export const setTokenDataStorage = (
tokenDataCacheStorage: typeof tokenDataStorage
) => {
tokenDataStorage = tokenDataCacheStorage;
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { NftEnumType } from 'types/tokens.types';
import {
FungibleTransactionType,
ISignTransactionsModalData,
SignEventsEnum
SignEventsEnum,
TokenType
} from './types/signTransactionsModal.types';

interface IEventBus {
Expand All @@ -22,7 +25,10 @@ export class SignTransactionsStateManager<T extends IEventBus = IEventBus> {

// whole data to be sent on update events
private initialData: ISignTransactionsModalData = {
transaction: null
commonData: { transactionsCount: 0, egldLabel: '', currentIndex: 0 },
tokenTransaction: null,
nftTransaction: null,
sftTransaction: null
};

private data: ISignTransactionsModalData = { ...this.initialData };
Expand All @@ -46,9 +52,11 @@ export class SignTransactionsStateManager<T extends IEventBus = IEventBus> {
return SignTransactionsStateManager.instance as SignTransactionsStateManager<U>;
}

public updateTransaction(members: Partial<ISignTransactionsModalData>): void {
this.data = {
...this.data,
public updateCommonData(
members: Partial<ISignTransactionsModalData['commonData']>
): void {
this.data.commonData = {
...this.data.commonData,
...members
};
this.notifyDataUpdate();
Expand All @@ -67,4 +75,36 @@ export class SignTransactionsStateManager<T extends IEventBus = IEventBus> {
private notifyDataUpdate(): void {
this.eventBus.publish(SignEventsEnum.DATA_UPDATE, this.data);
}

public updateTokenTransaction(
tokenData: ISignTransactionsModalData['tokenTransaction']
): void {
this.data.tokenTransaction = tokenData;
this.data.sftTransaction = null;
this.data.nftTransaction = null;

this.notifyDataUpdate();
}

public updateFungibleTransaction(
type: TokenType,
fungibleData: FungibleTransactionType
): void {
switch (type) {
case NftEnumType.NonFungibleESDT:
this.data.nftTransaction = fungibleData;
this.data.tokenTransaction = null;
this.data.sftTransaction = null;
break;
case NftEnumType.SemiFungibleESDT:
this.data.sftTransaction = fungibleData;
this.data.nftTransaction = null;
this.data.tokenTransaction = null;
break;
default:
break;
}

this.notifyDataUpdate();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,44 @@
export interface ITransactionData {
receiver?: string;
data?: string;
value?: string;
}

export type FungibleTransactionType = {
amount: string;
identifier?: string;
imageURL: string;
};

export type TokenType =
| 'SemiFungibleESDT'
| 'NonFungibleESDT'
| 'FungibleESDT'
| null;

export interface ISignTransactionsModalData {
transaction: ITransactionData | null;
shouldClose?: true;
commonData: {
receiver?: string;
data?: string;
transactionsCount: number;
/**
* Token type of the transaction.
* @param {string} `null` - if is EGLD or MultiEsdt transaction.
*/
tokenType?: TokenType;
egldLabel: string;
feeLimit?: string;
feeInFiatLimit?: string | null;
currentIndex: number;
};
tokenTransaction: {
identifier?: string;
amount: string;
usdValue: string;
} | null;
nftTransaction: FungibleTransactionType | null;
sftTransaction: FungibleTransactionType | null;
}

export enum SignEventsEnum {
Expand Down
Loading

0 comments on commit 079d116

Please sign in to comment.