Skip to content

Commit

Permalink
Merge branch 'pierregee/evm-convert-screen' into chloe/address-book-td
Browse files Browse the repository at this point in the history
  • Loading branch information
chloezxyy committed Oct 9, 2023
2 parents dc3f952 + 4a87561 commit 5443223
Show file tree
Hide file tree
Showing 10 changed files with 483 additions and 103 deletions.
3 changes: 3 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ module.exports = function (api) {
},
],
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-transform-private-methods",
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-private-property-in-object",
"react-native-reanimated/plugin",
];

Expand Down
10 changes: 8 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ services:
ports:
- "19553:80"
- "19552:8080"
- "19551:8082"
# - "19551:8082"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"

defi-blockchain:
image: defi/defichain:master-b352814976
image: defi/defichain:4.0.0-beta14
ports:
- "19554:19554"
- "19551:19551"
command: >
defid
-printtoconsole
-rpcallowip=0.0.0.0/0
-rpcbind=0.0.0.0
-ethrpcbind=0.0.0.0
-rpcuser=playground
-rpcpassword=playground
-rpcworkqueue=512
Expand Down Expand Up @@ -55,6 +59,8 @@ services:
-grandcentralheight=16
-grandcentralepilogueheight=17
-nextnetworkupgradeheight=18
environment:
- RUST_LOG=debug

defi-playground:
image: ghcr.io/birthdayresearch/playground-api:4.0.0-rc.1.2
Expand Down
197 changes: 153 additions & 44 deletions mobile-app/app/api/transaction/transfer_domain.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { translate } from "@translations";
import BigNumber from "bignumber.js";
import { ethers, providers, utils } from "ethers";
import { DfTxSigner } from "@waveshq/walletkit-ui/dist/store";
import { WhaleWalletAccount } from "@defichain/whale-api-wallet";
import {
CTransactionSegWit,
TransactionSegWit,
TransferDomain,
Script,
} from "@defichain/jellyfish-transaction";
import { fromAddress, Eth } from "@defichain/jellyfish-address";
import { NetworkName } from "@defichain/jellyfish-network";
import { ConvertDirection } from "@screens/enum";
import { parseUnits } from "ethers/lib/utils";
import TransferDomainV1 from "../../contracts/TransferDomainV1.json";

const TD_CONTRACT_ADDR = "0xdf00000000000000000000000000000000000001";

const TRANSFER_DOMAIN_TYPE = {
DVM: 2,
Expand All @@ -20,52 +28,78 @@ export interface TransferDomainToken {
balance: BigNumber;
}

export async function transferDomainSigner(
account: WhaleWalletAccount,
sourceTokenId: string,
targetTokenId: string,
amount: BigNumber,
convertDirection: ConvertDirection,
): Promise<CTransactionSegWit> {
const dvmScript = await account.getScript();
const evmScript = await account.getEvmScript();
interface TransferDomainSigner {
account: WhaleWalletAccount;
sourceTokenId: string;
targetTokenId: string;
amount: BigNumber;
convertDirection: ConvertDirection;
dvmAddress: string;
evmAddress: string;
networkName: NetworkName;
}

export async function transferDomainSigner({
account,
sourceTokenId,
targetTokenId,
amount,
convertDirection,
dvmAddress,
evmAddress,
networkName,
}: TransferDomainSigner): Promise<CTransactionSegWit> {
const dvmScript = fromAddress(dvmAddress, networkName)?.script as Script;
const evmScript = Eth.fromAddress(evmAddress) as Script;
const builder = account.withTransactionBuilder();

const [sourceScript, dstScript] =
convertDirection === ConvertDirection.evmToDvm
? [evmScript, dvmScript]
: [dvmScript, evmScript];
const isEvmToDvm = convertDirection === ConvertDirection.evmToDvm;

const [srcDomain, dstDomain] =
convertDirection === ConvertDirection.evmToDvm
? [TRANSFER_DOMAIN_TYPE.EVM, TRANSFER_DOMAIN_TYPE.DVM]
: [TRANSFER_DOMAIN_TYPE.DVM, TRANSFER_DOMAIN_TYPE.EVM];
const [sourceScript, dstScript] = isEvmToDvm
? [evmScript, dvmScript]
: [dvmScript, evmScript];

const signed: TransactionSegWit = await builder.account.transferDomain(
{
items: [
{
src: {
address: sourceScript,
amount: {
token: stripEvmSuffixFromTokenId(sourceTokenId),
amount,
},
domain: srcDomain,
data: new Uint8Array([]),
const [srcDomain, dstDomain] = isEvmToDvm
? [TRANSFER_DOMAIN_TYPE.EVM, TRANSFER_DOMAIN_TYPE.DVM]
: [TRANSFER_DOMAIN_TYPE.DVM, TRANSFER_DOMAIN_TYPE.EVM];

const signedEvmTxData = await createSignedEvmTx({
isEvmToDvm,
sourceTokenId,
targetTokenId,
amount,
dvmAddress,
evmAddress,
privateKey: await account.privateKey(),
});

const transferDomain: TransferDomain = {
items: [
{
src: {
address: sourceScript,
domain: srcDomain,
amount: {
token: stripEvmSuffixFromTokenId(sourceTokenId),
amount: amount,
},
dst: {
address: dstScript,
amount: {
token: stripEvmSuffixFromTokenId(targetTokenId),
amount,
},
domain: dstDomain,
data: new Uint8Array([]),
data: isEvmToDvm ? signedEvmTxData : new Uint8Array([]),
},
dst: {
address: dstScript,
domain: dstDomain,
amount: {
token: stripEvmSuffixFromTokenId(targetTokenId),
amount: amount,
},
data: isEvmToDvm ? new Uint8Array([]) : signedEvmTxData,
},
],
},
},
],
};

const signed = await builder.account.transferDomain(
transferDomain,
dvmScript,
);

Expand All @@ -77,6 +111,7 @@ export function transferDomainCrafter(
convertDirection: ConvertDirection,
sourceToken: TransferDomainToken,
targetToken: TransferDomainToken,
networkName: NetworkName,
onBroadcast: () => any,
onConfirmation: () => void,
submitButtonLabel?: string,
Expand All @@ -96,13 +131,16 @@ export function transferDomainCrafter(

return {
sign: async (account: WhaleWalletAccount) =>
await transferDomainSigner(
await transferDomainSigner({
account,
sourceToken.tokenId,
targetToken.tokenId,
amount,
convertDirection,
),
networkName,
sourceTokenId: sourceToken.tokenId,
targetTokenId: targetToken.tokenId,
dvmAddress: await account.getAddress(),
evmAddress: await account.getEvmAddress(),
}),
title: translate(
"screens/ConvertConfirmScreen",
"Convert {{amount}} {{symbolA}} to {{symbolB}} tokens",
Expand Down Expand Up @@ -142,9 +180,80 @@ export function transferDomainCrafter(
};
}

interface EvmTxSigner {
isEvmToDvm: boolean;
sourceTokenId: string;
targetTokenId: string;
amount: BigNumber;
dvmAddress: string;
evmAddress: string;
privateKey: Buffer;
}

async function createSignedEvmTx({
isEvmToDvm,
sourceTokenId,
targetTokenId,
amount,
dvmAddress,
evmAddress,
privateKey,
}: EvmTxSigner): Promise<Uint8Array> {
let data;
const tdFace = new utils.Interface(TransferDomainV1.abi);
const from = isEvmToDvm ? evmAddress : TD_CONTRACT_ADDR;
const to = isEvmToDvm ? TD_CONTRACT_ADDR : evmAddress;
// TODO: round off parsedAmount to 8 decimals
const parsedAmount = parseUnits(amount.toString(), 18); // TODO: Get decimals from token contract
const vmAddress = dvmAddress;

if (sourceTokenId === "0" || targetTokenId === "0") {
/* For DFI, use `transfer` function */
const transferDfi = [from, to, parsedAmount, vmAddress];
data = tdFace.encodeFunctionData("transfer", transferDfi);
} else {
/* For DST20, use `transferDST20` function */
const dst20TokenId = stripEvmSuffixFromTokenId(sourceTokenId);
const contractAddress = getAddressFromDST20TokenId(dst20TokenId);
const transferDST20 = [contractAddress, from, to, parsedAmount, vmAddress];
data = tdFace.encodeFunctionData("transferDST20", transferDST20);
}

// TODO: Make ETH RPC URL dynamic based on network
// const ethRpc = new providers.JsonRpcProvider("http://localhost:19551"); // TODO: Uncomment
const wallet = new ethers.Wallet(privateKey);

/* TODO: Figure out CORS issue when using the ethRpc */
const tx: providers.TransactionRequest = {
to: TD_CONTRACT_ADDR,
nonce: 0, // await ethRpc.getTransactionCount(from), // TODO: Remove hardcoded data
chainId: 1133, // (await rpc.getNetwork()).chainId, // TODO: Remove hardcoded data
data: data,
value: 0,
gasLimit: 0,
gasPrice: 0,
type: 0,
};
const evmtxSigned = (await wallet.signTransaction(tx)).substring(2); // rm prefix `0x`
return new Uint8Array(Buffer.from(evmtxSigned, "hex") || []);
}

function stripEvmSuffixFromTokenId(tokenId: string) {
if (tokenId.includes("-EVM")) {
return Number(tokenId.replace("-EVM", ""));
}
return Number(tokenId);
}

/**
* Get DST20 contract address
* https://github.com/DeFiCh/ain/blob/f5a671362f9899080d0a0dddbbcdcecb7c19d9e3/lib/ain-contracts/src/lib.rs#L79
*/
function getAddressFromDST20TokenId(tokenId: number): string {
const parsedTokenId = BigInt(tokenId);
const numberStr = parsedTokenId.toString(16); // Convert parsedTokenId to hexadecimal
const paddedNumberStr = numberStr.padStart(38, "0"); // Pad with zeroes to the left
const finalStr = `ff${paddedNumberStr}`;
const tokenContractAddess = utils.getAddress(finalStr);
return tokenContractAddess;
}
8 changes: 4 additions & 4 deletions mobile-app/app/contexts/FeatureFlagContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function useFeatureFlagContext(): FeatureFlagContextI {
}

export function FeatureFlagProvider(
props: React.PropsWithChildren<any>
props: React.PropsWithChildren<any>,
): JSX.Element | null {
const { network } = useNetworkContext();
const { url, isCustomUrl } = useServiceProviderContext();
Expand Down Expand Up @@ -80,7 +80,7 @@ export function FeatureFlagProvider(
satisfies(appVersion, flag.version) &&
flag.networks?.includes(network) &&
flag.id === featureId &&
flag.stage === "beta"
flag.stage === "beta",
);
}

Expand Down Expand Up @@ -118,7 +118,7 @@ export function FeatureFlagProvider(
}

const updateEnabledFeatures = async (
flags: FeatureFlagID[]
flags: FeatureFlagID[],
): Promise<void> => {
setEnabledFeatures(flags);
await FeatureFlagPersistence.set(flags);
Expand Down Expand Up @@ -151,7 +151,7 @@ export function FeatureFlagProvider(
satisfies(appVersion, flag.version) &&
flag.networks?.includes(network) &&
flag.platforms?.includes(Platform.OS) &&
flag.stage === "beta"
flag.stage === "beta",
),
};

Expand Down
19 changes: 19 additions & 0 deletions mobile-app/app/contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# ABI Source Explanation

**`/contracts`** directory contains the ABI (Application Binary Interface) for the "TransferDomainV1" smart contract. The ABI was generated based on the corresponding Solidity (.sol) file.

## Contract Information

- **Contract Name**: TransferDomainV1
- **Solidity File**: [TransferDomainV1.sol](https://github.com/DeFiCh/ain/blob/master/lib/ain-contracts/transfer_domain_v1/TransferDomainV1.sol)

## ABI Generation

The ABI provided in this repository was generated from the linked Solidity file. This ABI is essential for interacting with the TransferDomainV1 smart contract on the Ethereum blockchain or other compatible blockchains.

## Disclaimer

Please note that the ABI provided here is based on the linked Solidity file at the time of generation. Ensure that the Solidity code and the ABI are up-to-date and compatible with the version of the smart contract deployed on the blockchain you intend to interact with.

For any updates or changes to the contract, refer to the original source repository:
[TransferDomainV1.sol](https://github.com/DeFiCh/ain/blob/master/lib/ain-contracts/transfer_domain_v1/TransferDomainV1.sol)
Loading

0 comments on commit 5443223

Please sign in to comment.