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

feat(core): add evmtx signer on convert #4038

Merged
merged 21 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a2e2275
feat(core): add evmtx signer on convert
lykalabrada Sep 27, 2023
0c68bb3
Merge branch 'pierregee/evm-convert-screen' into lyka/sign-evmtx
lykalabrada Sep 27, 2023
8183f5d
feat(core): fix evmxt 'to' address for dvm to evm transferdomain
lykalabrada Sep 27, 2023
585771e
feat(core): update transferdomain implementation for dst20 tokens
lykalabrada Sep 28, 2023
57e775b
feat(core): update handle transferdomain tokenId for EVM tokens
lykalabrada Sep 29, 2023
ce56140
update docker
lykalabrada Oct 2, 2023
b544c75
update evmtx signature
lykalabrada Oct 2, 2023
f600737
update check for dfi token
lykalabrada Oct 3, 2023
a205bc0
add function to get dst20 token contract address
lykalabrada Oct 3, 2023
6e84732
fix(conflict): fix merge conflict
lykalabrada Oct 3, 2023
bbb1134
revert unnecessary changes on feautureflagcontext
lykalabrada Oct 3, 2023
69a9e18
update blockchain node to beta14
lykalabrada Oct 5, 2023
d556cf9
feat(core): implement transfer domain with signed evmtx on Send
lykalabrada Oct 5, 2023
086f7e5
add README.md for the contractA abi
lykalabrada Oct 5, 2023
02067cd
extraxt evmtx signer into a separate function
lykalabrada Oct 5, 2023
28a9800
Merge branch 'pierregee/evm-convert-screen' into lyka/sign-evmtx
lykalabrada Oct 5, 2023
50b476c
add todo
lykalabrada Oct 6, 2023
c67cac2
Merge branch 'lyka/sign-evmtx' of github.com:DeFiCh/wallet into lyka/…
lykalabrada Oct 6, 2023
7ffa287
Merge branch 'pierregee/evm-convert-screen' into lyka/sign-evmtx
lykalabrada Oct 6, 2023
ae7d91e
remove commented line
lykalabrada Oct 6, 2023
1ed2b7c
set nonce to 0
lykalabrada Oct 6, 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
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"
Copy link
Contributor

Choose a reason for hiding this comment

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

any implication on commenting this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't see any implication yet while performing tests on local playground 👀

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,
pierregee marked this conversation as resolved.
Show resolved Hide resolved
};
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