diff --git a/mobile-app/App.tsx b/mobile-app/App.tsx
index 8dd0926798..b841265c61 100644
--- a/mobile-app/App.tsx
+++ b/mobile-app/App.tsx
@@ -128,7 +128,7 @@ export default function App(): JSX.Element | null {
renderType={customToast}
>
-
+
diff --git a/mobile-app/app/api/transaction/transfer_domain.ts b/mobile-app/app/api/transaction/transfer_domain.ts
index 277b3f79d8..0eced51a21 100644
--- a/mobile-app/app/api/transaction/transfer_domain.ts
+++ b/mobile-app/app/api/transaction/transfer_domain.ts
@@ -13,10 +13,8 @@ import { fromAddress, Eth } from "@defichain/jellyfish-address";
import { NetworkName } from "@defichain/jellyfish-network";
import { ConvertDirection } from "@screens/enum";
import TransferDomainV1 from "@shared-contracts/TransferDomainV1.json";
-import { getEthRpcUrl } from "@contexts/CustomServiceProvider";
-import { SecuredStoreAPI } from "@api/secured";
-const TD_CONTRACT_ADDR = "0xdf00000000000000000000000000000000000001";
+export const TD_CONTRACT_ADDR = "0xdf00000000000000000000000000000000000001";
const TRANSFER_DOMAIN_TYPE = {
DVM: 2,
@@ -38,7 +36,9 @@ interface TransferDomainSigner {
convertDirection: ConvertDirection;
dvmAddress: string;
evmAddress: string;
+ chainId?: number;
networkName: NetworkName;
+ nonce: number;
}
export async function transferDomainSigner({
@@ -49,7 +49,9 @@ export async function transferDomainSigner({
convertDirection,
dvmAddress,
evmAddress,
+ chainId,
networkName,
+ nonce,
}: TransferDomainSigner): Promise {
const dvmScript = fromAddress(dvmAddress, networkName)?.script as Script;
const evmScript = Eth.fromAddress(evmAddress) as Script;
@@ -65,15 +67,6 @@ export async function transferDomainSigner({
? [TRANSFER_DOMAIN_TYPE.EVM, TRANSFER_DOMAIN_TYPE.DVM]
: [TRANSFER_DOMAIN_TYPE.DVM, TRANSFER_DOMAIN_TYPE.EVM];
- const privateKey = await account.privateKey();
- const accountEvmAddress = await account.getEvmAddress();
-
- // TODO (lyka): Check android issue with null eth provider
- const network = await SecuredStoreAPI.getNetwork();
- const ethRpc = new providers.JsonRpcProvider(getEthRpcUrl(network));
- const nonce = await ethRpc.getTransactionCount(accountEvmAddress);
- const chainId = (await ethRpc.getNetwork()).chainId;
-
const signedEvmTxData = await createSignedEvmTx({
isEvmToDvm,
sourceTokenId: stripEvmSuffixFromTokenId(sourceTokenId).toString(),
@@ -81,8 +74,8 @@ export async function transferDomainSigner({
amount,
dvmAddress,
evmAddress,
- accountEvmAddress,
- privateKey,
+ accountEvmAddress: await account.getEvmAddress(),
+ privateKey: await account.privateKey(),
chainId,
nonce,
});
@@ -159,9 +152,11 @@ export function transferDomainCrafter({
networkName,
onBroadcast,
onConfirmation,
+ chainId,
submitButtonLabel,
dvmAddress,
evmAddress,
+ nonce,
}: {
amount: BigNumber;
convertDirection: ConvertDirection;
@@ -170,9 +165,11 @@ export function transferDomainCrafter({
networkName: NetworkName;
onBroadcast: () => any;
onConfirmation: () => void;
+ chainId?: number;
submitButtonLabel?: string;
dvmAddress: string;
evmAddress: string;
+ nonce: number;
}): DfTxSigner {
if (
![ConvertDirection.evmToDvm, ConvertDirection.dvmToEvm].includes(
@@ -204,6 +201,8 @@ export function transferDomainCrafter({
targetTokenId: targetToken.tokenId,
dvmAddress,
evmAddress,
+ chainId,
+ nonce,
}),
title: translate(
"screens/ConvertConfirmScreen",
@@ -305,7 +304,7 @@ async function createSignedEvmTx({
return new Uint8Array(Buffer.from(evmtxSigned, "hex") || []);
}
-function stripEvmSuffixFromTokenId(tokenId: string) {
+export function stripEvmSuffixFromTokenId(tokenId: string) {
if (tokenId.includes("_evm")) {
return Number(tokenId.replace("_evm", ""));
}
diff --git a/mobile-app/app/contexts/CustomServiceProvider.tsx b/mobile-app/app/contexts/CustomServiceProvider.tsx
index 9a085b9fb4..c9911fd2ff 100644
--- a/mobile-app/app/contexts/CustomServiceProvider.tsx
+++ b/mobile-app/app/contexts/CustomServiceProvider.tsx
@@ -102,7 +102,7 @@ function getBlockscoutUrl(network: EnvironmentNetwork) {
}
}
-export function getEthRpcUrl(network: EnvironmentNetwork) {
+function getEthRpcUrl(network: EnvironmentNetwork) {
// TODO: Add proper ethereum RPC URLs for each network
switch (network) {
case EnvironmentNetwork.LocalPlayground:
@@ -111,11 +111,11 @@ export function getEthRpcUrl(network: EnvironmentNetwork) {
case EnvironmentNetwork.DevNet:
case EnvironmentNetwork.Changi:
return "http://34.34.156.49:20551"; // TODO: add final eth rpc url for changi, devnet and remote playground
- case EnvironmentNetwork.TestNet:
- return "http://34.38.30.102:18551"; // TODO: add final eth rpc url for testnet, with proper domain name
case EnvironmentNetwork.MainNet:
- default:
return "https://changi.dfi.team"; // TODO: add final eth rpc url for mainnet, with proper domain name
+ case EnvironmentNetwork.TestNet:
+ default:
+ return "http://34.38.30.102:18551"; // TODO: add final eth rpc url for testnet, with proper domain name
}
}
diff --git a/mobile-app/app/contexts/EVMProvider.tsx b/mobile-app/app/contexts/EVMProvider.tsx
index 91ca10dd2f..b9eee0a68e 100644
--- a/mobile-app/app/contexts/EVMProvider.tsx
+++ b/mobile-app/app/contexts/EVMProvider.tsx
@@ -7,6 +7,7 @@ import React, {
} from "react";
import { providers } from "ethers";
import { useNetworkContext } from "@waveshq/walletkit-ui";
+import { BaseLogger } from "@waveshq/walletkit-ui/dist/contexts/logger";
import { useCustomServiceProviderContext } from "./CustomServiceProvider";
interface EVMProviderContextI {
@@ -21,7 +22,8 @@ export function useEVMProvider(): EVMProviderContextI {
export function EVMProvider({
children,
-}: React.PropsWithChildren): JSX.Element | null {
+ logger,
+}: React.PropsWithChildren<{ logger: BaseLogger }>): JSX.Element | null {
const { ethRpcUrl } = useCustomServiceProviderContext();
const { network } = useNetworkContext();
const [chainId, setChainId] = useState();
@@ -35,7 +37,10 @@ export function EVMProvider({
const { chainId } = await provider.getNetwork();
setChainId(chainId);
setProvider(provider);
+ logger.info(`ChainID: ${chainId}`);
} catch (e) {
+ logger.info(`Eth rpc url: ${ethRpcUrl}`);
+ logger.error(e);
// Note: Added this for cases wherein eth rpc url is invalid or unreachable
setChainId(0);
setProvider(null);
diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx
index 518bbb5604..85aabe9a43 100644
--- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx
+++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/components/PortfolioCard.tsx
@@ -122,7 +122,6 @@ function PortfolioItemRow({
displaySymbol={token.displaySymbol}
name={token.name}
testID={testID}
- isEvmDomain={isEvmDomain}
/>
- {tokenName}
+ {name}
)}
diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts
index 7d742e6668..6f5e7b4fef 100644
--- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts
+++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/hooks/EvmTokenBalances.ts
@@ -75,7 +75,7 @@ export function useEvmTokenBalances(): { evmTokens: WalletToken[] } {
isDAT: tokenDetails.isDAT,
isLPS: tokenDetails.isLPS,
isLoanToken: tokenDetails.isLoanToken,
- name: `${tokenDetails.name} for EVM`,
+ name: `${tokenDetails.name || tokenDetails.symbol} for EVM`,
displaySymbol: tokenDetails.displaySymbol,
avatarSymbol: tokenDetails.symbol,
amount: utils.formatUnits(each.value, each?.token?.decimals),
diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx
index 1ece2dc920..c5e8278818 100644
--- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx
+++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/ConvertConfirmationScreen.tsx
@@ -33,6 +33,7 @@ import {
} from "@api/transaction/transfer_domain";
import { useNetworkContext } from "@waveshq/walletkit-ui";
import { NetworkName } from "@defichain/jellyfish-network";
+import { useEVMProvider } from "@contexts/EVMProvider";
import { PortfolioParamList } from "../PortfolioNavigator";
type Props = StackScreenProps;
@@ -48,6 +49,7 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element {
} = route.params;
const { networkName } = useNetworkContext();
const { address, evmAddress } = useWalletContext();
+ const { provider, chainId } = useEVMProvider();
const addressLabel = useAddressLabel(address);
const hasPendingJob = useSelector((state: RootState) =>
hasTxQueued(state.transactionQueue),
@@ -120,6 +122,9 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element {
logger,
);
} else {
+ const nonce = provider
+ ? await provider.getTransactionCount(evmAddress)
+ : 0;
await constructSignedTransferDomain(
{
amount,
@@ -127,6 +132,8 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element {
sourceToken,
targetToken,
networkName,
+ chainId,
+ nonce,
evmAddress,
dvmAddress: address,
},
@@ -193,7 +200,11 @@ export function ConvertConfirmationScreen({ route }: Props): JSX.Element {
? "DFI (EVM)"
: targetToken.displaySymbol
}
- fromAddress={address}
+ fromAddress={
+ convertDirection === ConvertDirection.evmToDvm
+ ? evmAddress
+ : address
+ }
fromAddressLabel={addressLabel}
isEvmToken={convertDirection === ConvertDirection.dvmToEvm}
/>
@@ -348,16 +359,20 @@ async function constructSignedTransferDomain(
sourceToken,
targetToken,
networkName,
+ chainId,
dvmAddress,
evmAddress,
+ nonce,
}: {
convertDirection: ConvertDirection;
sourceToken: TransferDomainToken;
targetToken: TransferDomainToken;
amount: BigNumber;
networkName: NetworkName;
+ chainId?: number;
dvmAddress: string;
evmAddress: string;
+ nonce: number;
},
dispatch: Dispatch,
onBroadcast: () => void,
@@ -374,8 +389,10 @@ async function constructSignedTransferDomain(
networkName,
onBroadcast,
onConfirmation: () => {},
+ chainId,
dvmAddress,
evmAddress,
+ nonce,
}),
),
);
diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx
index 144cecee2b..e2ecddfc61 100644
--- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx
+++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/SendConfirmationScreen.tsx
@@ -50,6 +50,7 @@ import {
AddressType as JellyfishAddressType,
} from "@waveshq/walletkit-core";
import { DomainType, useDomainContext } from "@contexts/DomainContext";
+import { useEVMProvider } from "@contexts/EVMProvider";
import { PortfolioParamList } from "../PortfolioNavigator";
type Props = StackScreenProps;
@@ -80,6 +81,7 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element {
hasOceanTXQueued(state.ocean),
);
const dispatch = useAppDispatch();
+ const { provider, chainId } = useEVMProvider();
const [isSubmitting, setIsSubmitting] = useState(false);
const navigation = useNavigation>();
const [isOnPage, setIsOnPage] = useState(true);
@@ -99,12 +101,15 @@ export function SendConfirmationScreen({ route }: Props): JSX.Element {
return;
}
setIsSubmitting(true);
+ const nonce = provider ? await provider.getTransactionCount(evmAddress) : 0;
await send(
{
address: destination,
token,
amount,
domain,
+ chainId,
+ nonce,
networkName: network.networkName,
},
dispatch,
@@ -359,11 +364,13 @@ interface SendForm {
address: string;
token: WalletToken;
domain: DomainType;
+ nonce: number;
+ chainId?: number;
networkName: NetworkName;
}
async function send(
- { address, token, amount, domain, networkName }: SendForm,
+ { address, token, amount, domain, networkName, nonce, chainId }: SendForm,
dispatch: Dispatch,
onBroadcast: () => void,
logger: NativeLoggingProps,
@@ -417,6 +424,8 @@ async function send(
dvmAddress,
evmAddress,
networkName,
+ nonce,
+ chainId,
convertDirection: sendDirection,
});
}
diff --git a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx
index f161b02d27..d92d7a6674 100644
--- a/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx
+++ b/mobile-app/app/screens/AppNavigator/screens/Portfolio/screens/TokenDetailScreen.tsx
@@ -13,7 +13,10 @@ import {
unifiedDFISelector,
WalletToken,
} from "@waveshq/walletkit-ui/dist/store";
-import { useDeFiScanContext } from "@shared-contexts/DeFiScanContext";
+import {
+ getMetaScanTokenUrl,
+ useDeFiScanContext,
+} from "@shared-contexts/DeFiScanContext";
import { PoolPairData } from "@defichain/whale-api-client/dist/api/poolpairs";
import { View } from "@components";
import {
@@ -31,6 +34,7 @@ import { InfoTextLinkV2 } from "@components/InfoTextLink";
import { ThemedTouchableListItem } from "@components/themed/ThemedTouchableListItem";
import { ConvertDirection } from "@screens/enum";
import { DomainType, useDomainContext } from "@contexts/DomainContext";
+import { useNetworkContext } from "@waveshq/walletkit-ui";
import { PortfolioParamList } from "../PortfolioNavigator";
import { useTokenPrice } from "../hooks/TokenPrice";
import { useDenominationCurrency } from "../hooks/PortfolioCurrency";
@@ -447,6 +451,7 @@ function TokenSummary(props: {
}): JSX.Element {
const { denominationCurrency } = useDenominationCurrency();
const { getTokenUrl } = useDeFiScanContext();
+ const { network } = useNetworkContext();
const onTokenUrlPressed = async (): Promise => {
const id =
props.token.id === "0_utxo" ||
@@ -454,7 +459,9 @@ function TokenSummary(props: {
props.token.id === "0_evm"
? 0
: props.token.id;
- const url = getTokenUrl(id);
+ const url = props.token.id.includes("_evm")
+ ? getMetaScanTokenUrl(network, props.token.id)
+ : getTokenUrl(id);
await Linking.openURL(url);
};
@@ -488,7 +495,7 @@ function TokenSummary(props: {
dark={tailwind("text-mono-dark-v2-700")}
style={tailwind("text-sm font-normal-v2")}
>
- {props.token.name}
+ {props.token.name || props.token.symbol}
diff --git a/shared/contexts/DeFiScanContext.tsx b/shared/contexts/DeFiScanContext.tsx
index c841872127..48c7cd813b 100644
--- a/shared/contexts/DeFiScanContext.tsx
+++ b/shared/contexts/DeFiScanContext.tsx
@@ -1,6 +1,11 @@
import React, { createContext, useContext, useMemo } from "react";
import { EnvironmentNetwork } from "@waveshq/walletkit-core";
import { useNetworkContext } from "@waveshq/walletkit-ui";
+import {
+ TD_CONTRACT_ADDR,
+ getAddressFromDST20TokenId,
+ stripEvmSuffixFromTokenId,
+} from "@api/transaction/transfer_domain";
interface DeFiScanContextI {
getTransactionUrl: (txid: string, rawtx?: string) => string;
@@ -14,13 +19,14 @@ interface DeFiScanContextI {
const DeFiScanContext = createContext(undefined as any);
const baseDefiScanUrl = "https://defiscan.live";
+const baseMetaScanUrl = "https://meta.defiscan.live";
export function useDeFiScanContext(): DeFiScanContextI {
return useContext(DeFiScanContext);
}
export function DeFiScanProvider(
- props: React.PropsWithChildren
+ props: React.PropsWithChildren,
): JSX.Element | null {
const { network } = useNetworkContext();
@@ -70,6 +76,8 @@ function getNetworkParams(network: EnvironmentNetwork): string {
case EnvironmentNetwork.LocalPlayground:
case EnvironmentNetwork.RemotePlayground:
return `?network=${EnvironmentNetwork.RemotePlayground}`;
+ case EnvironmentNetwork.Changi:
+ return `?network=${EnvironmentNetwork.Changi}`;
default:
return "";
}
@@ -78,7 +86,7 @@ function getNetworkParams(network: EnvironmentNetwork): string {
export function getTxURLByNetwork(
network: EnvironmentNetwork,
txid: string,
- rawtx?: string
+ rawtx?: string,
): string {
let baseUrl = `${baseDefiScanUrl}/transactions/${txid}`;
@@ -98,7 +106,24 @@ export function getTxURLByNetwork(
export function getURLByNetwork(
path: string,
network: EnvironmentNetwork,
- id: number | string
+ id: number | string,
): string {
return `${baseDefiScanUrl}/${path}/${id}${getNetworkParams(network)}`;
}
+
+export function getMetaScanTokenUrl(
+ network: EnvironmentNetwork,
+ id: string,
+): string {
+ const networkParams = getNetworkParams(network);
+ const tokenId = stripEvmSuffixFromTokenId(id);
+
+ // DFI token
+ if (tokenId === 0) {
+ return `${baseMetaScanUrl}/token/${TD_CONTRACT_ADDR}${networkParams}`;
+ }
+
+ // DST20 token
+ const tokenAddress = getAddressFromDST20TokenId(tokenId);
+ return `${baseMetaScanUrl}/token/${tokenAddress}${networkParams}`;
+}