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

Release/main/20240611 #3494

Merged
merged 15 commits into from
Jun 12, 2024
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
2 changes: 2 additions & 0 deletions src/app/core/constants/token.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ export enum ETokenNFTTypeBE {
CW721 = 'CW721_TOKEN',
ERC721 = 'ERC721_TOKEN',
}

export const TOKEN_EVM_BURNT = '0x0000000000000000000000000000000000000000';
4 changes: 4 additions & 0 deletions src/app/core/pipes/custom-pipe.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { BalancePipe, FormatDigitPipe, GtPipe, GtePipe, LtPipe, LtePipe } from '
import { ObjectKeysPipe } from './object-keys.pipe';
import { CombineTxsMsgPipe, EllipsisPipe } from './string.pipe';
import { NameTagTooltipPipe } from './tooltip.pipe';
import { HighlightFunctionPipe } from './highlight-function.pipe';

@NgModule({
imports: [CommonModule],
Expand Down Expand Up @@ -40,6 +41,7 @@ import { NameTagTooltipPipe } from './tooltip.pipe';
ObjectKeysPipe,
CapacityPipe,
EvmAddressPipe,
HighlightFunctionPipe,
],
exports: [
JsonPipe,
Expand All @@ -65,7 +67,9 @@ import { NameTagTooltipPipe } from './tooltip.pipe';
ObjectKeysPipe,
CapacityPipe,
EvmAddressPipe,
HighlightFunctionPipe,
],
providers: [],
})
export class CustomPipeModule {}

31 changes: 31 additions & 0 deletions src/app/core/pipes/highlight-function.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

@Pipe({ name: 'highlight_function' })
export class HighlightFunctionPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(value: string) {
if (!value) return null;
let replacedValue = value;
const parametersPattern = /\(([^)]+)\)/;
const parametersMatch = value.match(parametersPattern);
const parameters = parametersMatch ? parametersMatch[1]?.split(',')?.map((param) => param?.trim()) : [];

parameters.map((item) => {
const [dataType, modifier, name] = item?.split(' ') || [];
const dataTypeHTML = dataType
? `<span style="color: var(--aura-green-3); font-family: inherit">${dataType}</span>`
: '';
const modifierHTML = modifier
? `<span style="color: ${
!name ? 'var(--aura-red-3)' : 'var(--aura-gray-3)'
}; font-family: inherit">${modifier}</span>`
: '';
const nameHTML = name ? `<span style="color: var(--aura-red-3); font-family: inherit">${name}</span>` : '';

replacedValue = replacedValue?.replace(item, `${dataTypeHTML} ${modifierHTML} ${nameHTML}`);
});
return this.sanitizer.bypassSecurityTrustHtml(replacedValue);
}
}

11 changes: 6 additions & 5 deletions src/app/core/services/token.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { CW20_TRACKING } from '../constants/common.constant';
import { LCD_COSMOS } from '../constants/url.constant';
import { EnvironmentService } from '../data-services/environment.service';
import { CommonService } from './common.service';
import { TOKEN_EVM_BURNT } from '../constants/token.constant';

@Injectable({ providedIn: 'root' })
export class TokenService extends CommonService {
Expand Down Expand Up @@ -271,7 +272,7 @@ export class TokenService extends CommonService {
erc721_token(
limit: $limit
offset: $offset
where: {erc721_contract: {evm_smart_contract: {address: {_eq: $contract_address}}}, token_id: {_eq: $tokenId}, owner: {_eq: $owner, _nilike: "0x000000000%"}}
where: {erc721_contract: {evm_smart_contract: {address: {_eq: $contract_address}}}, token_id: {_eq: $tokenId}, owner: {_eq: $owner, _neq: "${TOKEN_EVM_BURNT}"}}
order_by: [{last_updated_height: desc}, {id: desc}]
) {
id
Expand All @@ -282,7 +283,7 @@ export class TokenService extends CommonService {
created_at
}
erc721_token_aggregate(
where: {erc721_contract: {evm_smart_contract: {address: {_eq: $contract_address}}}, token_id: {_eq: $tokenId}, owner: {_eq: $owner, _nilike: "0x000000000%"}}
where: {erc721_contract: {evm_smart_contract: {address: {_eq: $contract_address}}}, token_id: {_eq: $tokenId}, owner: {_eq: $owner, _neq: "${TOKEN_EVM_BURNT}"}}
) {
aggregate {
count
Expand Down Expand Up @@ -334,7 +335,7 @@ export class TokenService extends CommonService {
query queryCountTotalTokenErc721($contract_address: String) {
${this.envDB} {
erc721_token_aggregate(
where: {erc721_contract: {evm_smart_contract: {address: {_eq: $contract_address}}}, owner: {_nilike: "0x000000000%"}}
where: {erc721_contract: {evm_smart_contract: {address: {_eq: $contract_address}}}, owner: {_neq: "${TOKEN_EVM_BURNT}"}}
) {
aggregate {
count
Expand Down Expand Up @@ -423,15 +424,15 @@ export class TokenService extends CommonService {
view_count_holder_erc721(
limit: $limit
offset: $offset
where: {erc721_contract_address: {_eq: $contract_address}, owner: {_nilike: "0x000000000%"}}
where: {erc721_contract_address: {_eq: $contract_address}, owner: {_neq: "${TOKEN_EVM_BURNT}"}}
order_by: {count: desc}
) {
count
erc721_contract_address
owner
}
view_count_holder_erc721_aggregate(
where: {erc721_contract_address: {_eq: $contract_address}, owner: {_nilike: "0x000000000%"}}
where: {erc721_contract_address: {_eq: $contract_address}, owner: {_neq: "${TOKEN_EVM_BURNT}"}}
) {
aggregate {
count
Expand Down
50 changes: 43 additions & 7 deletions src/app/core/services/wallet.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { getGasPriceByChain } from '../utils/cosmoskit/helpers/gas';
import { ExtendsWalletClient } from '../utils/cosmoskit/wallets';
import { wallets as leapMetamask } from '../utils/cosmoskit/wallets/leap-metamask-cosmos-snap';
import { getSigner } from '../utils/ethers/ethers';
import { addNetwork, checkNetwork } from '../utils/ethers/utils';
import { addNetwork, checkNetwork, getMetamask } from '../utils/ethers/utils';
import local from '../utils/storage/local';

@Injectable({
Expand Down Expand Up @@ -146,7 +146,7 @@ export class WalletService implements OnDestroy {
await this._walletManager.onMounted();

this.accountChangeEvent();

this.evmChangeEvent();
return 'SUCCESS';
}

Expand Down Expand Up @@ -248,6 +248,17 @@ export class WalletService implements OnDestroy {
});
}

evmChangeEvent() {
const reconnect = () => {
const timeoutId = setTimeout(() => {
clearTimeout(timeoutId);
this.connectToChain();
}, 1000);
};
(window as any).ethereum?.on('accountsChanged', reconnect);
(window as any).ethereum?.on('chainChanged', reconnect);
}
Comment on lines +251 to +260
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize the event handling in evmChangeEvent to avoid potential memory leaks.

Consider removing the event listener when it's no longer needed to prevent memory leaks.


private async _getSigningCosmWasmClientAuto() {
let _walletName = localStorage.getItem(STORAGE_KEY.CURRENT_WALLET);
const chainWallet = this._walletManager.getMainWallet(_walletName);
Expand Down Expand Up @@ -340,7 +351,7 @@ export class WalletService implements OnDestroy {
}

getCosmosAccountOnly() {
return this.walletAccount;
return this.walletAccount;
}

getEvmAccount() {
Expand Down Expand Up @@ -411,10 +422,9 @@ export class WalletService implements OnDestroy {
}

async connectEvmWallet() {
const network = await checkNetwork(this.env.evmChainInfo.chainId);

if (!network) {
await addNetwork(this.env.evmChainInfo);
const connected = await this.connectToChain();
if (!connected) {
return;
Comment on lines +425 to +427
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling when the connection fails in connectEvmWallet.

Consider adding a user-friendly error message or logging when the connection fails.

}

getSigner(this.env.etherJsonRpc).then((signer) => {
Expand All @@ -433,6 +443,32 @@ export class WalletService implements OnDestroy {
});
}

async connectToChain() {
const metamask = getMetamask();
const chainId = '0x' + this.env.evmChainInfo.chainId.toString(16);
try {
await metamask.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: chainId }],
});
} catch (switchError: any) {
switch (switchError.code) {
case 4902:
// This error code indicates that the chain has not been added to MetaMask.
await addNetwork(this.env.evmChainInfo);
break;
case 4001:
// This error code : "User rejected the request."
return false;
case -32002:
// This error code : "Request of type 'wallet_switchEthereumChain' already pending"
return false;
}
}

return true;
}

parseAddress(address: string) {
return transferAddress(this.env.chainInfo.bech32Config.bech32PrefixAccAddr, address);
}
Expand Down
13 changes: 8 additions & 5 deletions src/app/core/utils/ethers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ export async function addNetwork(chain) {
chain.explorers && chain.explorers.length > 0 && chain.explorers[0].url ? chain.explorers[0].url : chain.infoURL,
],
};

return metamask.request({
method: 'wallet_addEthereumChain',
params: [params],
});
try {
await metamask.request({
method: 'wallet_addEthereumChain',
params: [params],
});
} catch (addError) {
console.error(addError);
}
}
9 changes: 7 additions & 2 deletions src/app/core/utils/ethers/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ export function validateAndParsingInput(type: JsonFragmentType, value: any) {
switch (type.type) {
case 'uint256':
case 'bytes4':
return value;
return { value };
case 'bool':
if (value?.toLowerCase() !== 'true' && value?.toLowerCase() !== 'false') {
return { value, error: `"${value}" is an invalid parameter, please use true/false.` };
}
return { value: value?.toLowerCase() === 'true' ? true : false };
Comment on lines +9 to +12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great improvement in type safety for boolean values. However, consider simplifying the return statement.

- return { value: value?.toLowerCase() === 'true' ? true : false };
+ return { value: value?.toLowerCase() === 'true' };

This change removes the unnecessary ternary operation, making the code cleaner and more efficient.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (value?.toLowerCase() !== 'true' && value?.toLowerCase() !== 'false') {
return { value, error: `"${value}" is an invalid parameter, please use true/false.` };
}
return { value: value?.toLowerCase() === 'true' ? true : false };
if (value?.toLowerCase() !== 'true' && value?.toLowerCase() !== 'false') {
return { value, error: `"${value}" is an invalid parameter, please use true/false.` };
}
return { value: value?.toLowerCase() === 'true' };
Tools
Biome

[error] 12-12: Unnecessary use of boolean literals in conditional expression. (lint/complexity/noUselessTernary)

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

default:
return value;
return { value };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ export class EvmContractContentComponent implements OnInit, OnDestroy {
next: (res) => {
this.contractTransaction['data'] = res;
this.contractTransaction['count'] = this.contractTransaction['data'].length || 0;
this.contractTransaction = {...this.contractTransaction};
},
error: (e) => {
if (e.name === TIMEOUT_ERROR) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { EnvironmentService } from 'src/app/core/data-services/environment.servi
import { READ_STATE_MUTABILITY } from 'src/app/core/models/evm-contract.model';
import { getEthersProvider } from 'src/app/core/utils/ethers';
import { validateAndParsingInput } from 'src/app/core/utils/ethers/validate';
import { WalletService } from '../../../../../../core/services/wallet.service';

type Error = {
code?: string;
message?: string
}
message?: string;
};

type JsonFragmentExtends = JsonFragment & {
formGroup?: FormGroup;
Expand Down Expand Up @@ -38,6 +39,7 @@ export class EvmReadComponent implements OnChanges {
constructor(
private environmentService: EnvironmentService,
private fb: FormBuilder,
private walletService: WalletService,
) {}

ngOnChanges(changes: SimpleChanges): void {
Expand Down Expand Up @@ -112,7 +114,7 @@ export class EvmReadComponent implements OnChanges {
}
}

handleQueryContract(jsonFragment: JsonFragmentExtends) {
async handleQueryContract(jsonFragment: JsonFragmentExtends) {
if (!jsonFragment) {
return;
}
Expand All @@ -132,6 +134,26 @@ export class EvmReadComponent implements OnChanges {
return validateAndParsingInput(i, value); // TODO
});

const errorParams = params.map((i) => i.error).filter((f) => f);
if (errorParams.length > 0) {
jsonFragment.isLoading = false;
jsonFragment.error = {
code: 'INVALID_ARGUMENT',
message: errorParams.join(' '),
};
return;
}

const connected = await this.walletService.connectToChain();
if (!connected) {
jsonFragment.isLoading = false;
jsonFragment.error = {
code: 'error',
message: `Please switch to ${this.environmentService.evmChainInfo.chain} chain.`,
};
return;
}

const contract = this.createContract();

if (!contract) {
Expand All @@ -141,7 +163,9 @@ export class EvmReadComponent implements OnChanges {
jsonFragment.isLoading = true;
jsonFragment.result = undefined;
jsonFragment.error = undefined;
contract[name]?.(...params)
const paramsData = params.map((i) => i.value);

contract[name]?.(...paramsData)
.then((res) => {
jsonFragment.result = res;
jsonFragment.isLoading = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,26 @@ export class EvmWriteComponent implements OnChanges {
return validateAndParsingInput(i, value); // TODO
});

const errorParams = params.map((i) => i.error).filter((f) => f);
if (errorParams.length > 0) {
jsonFragment.isLoading = false;
jsonFragment.error = {
code: 'INVALID_ARGUMENT',
message: errorParams.join(' '),
};
return;
}

const fundAmount = formControls['fund']?.value || '0';

const connected = await this.walletService.connectToChain();

if (!connected) {
jsonFragment.isLoading = false;
jsonFragment.error = { code: 'error', message: `Please switch to ${this.env.evmChainInfo.chain} chain.` };
return;
}

const contract = this.createContract();

if (!contract) {
Expand All @@ -163,9 +182,10 @@ export class EvmWriteComponent implements OnChanges {
jsonFragment.result = undefined;
jsonFragment.error = undefined;

const paramsData = params.map((i) => i.value);
const nameContract = `${name}(${paramsDes.join(',')})`;
const x = await contract[nameContract]?.estimateGas(...params).catch((e) => e);
contract[nameContract]?.(...params, {
const x = await contract[nameContract]?.estimateGas(...paramsData).catch((e) => e);
contract[nameContract]?.(...paramsData, {
gasLimit: Number(x) || 250_000,
gasPrice: 1_000_0000,
value: parseEther(fundAmount),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ <h1 class="fw-bold sub-text text--white mb-0 mr-1 break-word">
<h2 class="mb-0 h5-mob text--white card__ntf-detail-item" id="popupCopy">Details</h2>
<div class="card__ntf-detail-item body">
<div class="label-detail text--gray-5">Owner:</div>
<div class="d-flex align-items-center position-relative" *ngIf="nftDetail?.owner && !nftDetail?.burned">
<div class="d-flex align-items-center position-relative" *ngIf="nftDetail?.owner">
<app-name-tag
[value]="nftDetail?.owner"
[fullText]="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { EvmPopupShareComponent } from './evm-popup-share/evm-popup-share.compon
import { map, switchMap } from 'rxjs';
import { mappingMethodName } from '../../../global/global';
import { TransactionService } from '../../../core/services/transaction.service';
import { TOKEN_EVM_BURNT } from '../../../core/constants/token.constant';

@Component({
selector: 'app-nft-detail',
Expand All @@ -51,7 +52,7 @@ export class EvmNFTDetailComponent implements OnInit {
templates: Array<TableTemplate> = [
{ matColumnDef: 'tx_hash', headerCellDef: 'Txn Hash' },
{ matColumnDef: 'type', headerCellDef: 'Method' },
{ matColumnDef: 'status', headerCellDef: 'Result' },
// { matColumnDef: 'status', headerCellDef: 'Result' },
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented out the 'status' column in the table.

This change might affect the UI by removing important information about transaction results. Please confirm if this change aligns with the intended user experience.

{ matColumnDef: 'timestamp', headerCellDef: 'Time' },
{ matColumnDef: 'from_address', headerCellDef: 'From' },
{ matColumnDef: 'to_address', headerCellDef: 'To' },
Expand Down Expand Up @@ -155,7 +156,7 @@ export class EvmNFTDetailComponent implements OnInit {
name: _.get(res, 'erc721_contract.name'),
owner: res.owner,
creator: res.erc721_contract?.evm_smart_contract?.creator,
burned: res.owner?.startsWith('0x000000000'),
burned: res.owner === TOKEN_EVM_BURNT,
token_id: res.token_id,
media_info: res.media_info,
verification_status: _.get(res, 'erc721_contract.evm_smart_contract.evm_contract_verifications[0].status'),
Expand Down
Loading