wormhole/bridge_ui/src/utils/transferFrom.ts

99 lines
4.4 KiB
TypeScript
Raw Normal View History

import { ethers } from "ethers";
import { arrayify, formatUnits, parseUnits } from "ethers/lib/utils";
import { Bridge__factory, TokenImplementation__factory } from "../ethers-contracts";
import { ChainId, CHAIN_ID_ETH, CHAIN_ID_SOLANA, ETH_TOKEN_BRIDGE_ADDRESS, SOL_TOKEN_BRIDGE_ADDRESS } from "./consts";
// TODO: this should probably be extended from the context somehow so that the signatures match
// TODO: allow for / handle cancellation?
// TODO: overall better input checking and error handling
export function transferFromEth(provider: ethers.providers.Web3Provider | undefined, tokenAddress: string, amount: string, recipientChain: ChainId, recipientAddress: Uint8Array | undefined) {
if (!provider || !recipientAddress) return;
const signer = provider.getSigner();
if (!signer) return;
//TODO: check if token attestation exists on the target chain
//TODO: don't hardcode, fetch decimals / share them with balance, how do we determine recipient chain?
//TODO: more catches
const amountParsed = parseUnits(amount, 18);
signer.getAddress().then((signerAddress) => {
console.log("Signer:", signerAddress);
console.log("Token:", tokenAddress)
const token = TokenImplementation__factory.connect(
tokenAddress,
signer
);
token
.allowance(signerAddress, ETH_TOKEN_BRIDGE_ADDRESS)
.then((allowance) => {
console.log("Allowance", allowance.toString()); //TODO: should we check that this is zero and warn if it isn't?
token
.approve(ETH_TOKEN_BRIDGE_ADDRESS, amountParsed)
.then((transaction) => {
console.log(transaction);
const fee = 0; // for now, this won't do anything, we may add later
const nonceConst = Math.random() * 100000;
const nonceBuffer = Buffer.alloc(4);
nonceBuffer.writeUInt32LE(nonceConst, 0);
console.log("Initiating transfer");
console.log("Amount:", formatUnits(amountParsed, 18));
console.log("To chain:", recipientChain);
console.log("To address:", recipientAddress);
console.log("Fees:", fee);
console.log("Nonce:", nonceBuffer);
const bridge = Bridge__factory.connect(
ETH_TOKEN_BRIDGE_ADDRESS,
signer
);
bridge
.transferTokens(
tokenAddress,
amountParsed,
recipientChain,
recipientAddress,
fee,
nonceBuffer
)
.then((v) => console.log("Success:", v))
.catch((r) => console.error(r)); //TODO: integrate toast messages
});
});
});
}
// TODO: need to check transfer native vs transfer wrapped
// TODO: switch out targetProvider for generic address (this likely involves getting these in their respective contexts)
export function transferFromSolana(fromAddress: string | undefined, tokenAddress: string, amount: string, targetProvider: ethers.providers.Web3Provider | undefined, targetChain: ChainId) {
if (!fromAddress || !targetProvider) return;
const targetSigner = targetProvider.getSigner();
if (!targetSigner) return;
targetSigner.getAddress().then(targetAddressStr => {
const targetAddress = arrayify(targetAddressStr)
const nonceConst = Math.random() * 100000;
const nonceBuffer = Buffer.alloc(4);
nonceBuffer.writeUInt32LE(nonceConst, 0);
const nonce = nonceBuffer.readUInt32LE(0)
// TODO: check decimals
// should we avoid BigInt?
const amountParsed = BigInt(amount)
const fee = BigInt(0) // for now, this won't do anything, we may add later
console.log('bridge:',SOL_TOKEN_BRIDGE_ADDRESS)
console.log('from:',fromAddress)
console.log('token:',tokenAddress)
console.log('nonce:',nonce)
console.log('amount:',amountParsed)
console.log('fee:',fee)
console.log('target:',targetAddressStr,targetAddress)
console.log('chain:',targetChain)
// TODO: program_id vs bridge_id?
import("token-bridge").then(({transfer_native_ix})=>{
const ix = transfer_native_ix(SOL_TOKEN_BRIDGE_ADDRESS,SOL_TOKEN_BRIDGE_ADDRESS,fromAddress,fromAddress,tokenAddress,nonce,amountParsed,fee,targetAddress,targetChain)
console.log(ix)
})
})
}
const transferFrom = {
[CHAIN_ID_ETH]: transferFromEth,
[CHAIN_ID_SOLANA]: transferFromSolana
}
export default transferFrom