2021-07-30 11:13:53 -07:00
|
|
|
import { ethers } from "ethers";
|
2021-08-01 20:21:28 -07:00
|
|
|
import { arrayify, formatUnits, parseUnits } from "ethers/lib/utils";
|
2021-07-30 11:13:53 -07:00
|
|
|
import { Bridge__factory, TokenImplementation__factory } from "../ethers-contracts";
|
2021-08-01 20:21:28 -07:00
|
|
|
import { ChainId, CHAIN_ID_ETH, CHAIN_ID_SOLANA, ETH_TOKEN_BRIDGE_ADDRESS, SOL_TOKEN_BRIDGE_ADDRESS } from "./consts";
|
2021-07-30 11:13:53 -07:00
|
|
|
|
|
|
|
// 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
|
2021-08-01 20:21:28 -07:00
|
|
|
export function transferFromEth(provider: ethers.providers.Web3Provider | undefined, tokenAddress: string, amount: string, recipientChain: ChainId, recipientAddress: Uint8Array | undefined) {
|
2021-07-30 11:13:53 -07:00
|
|
|
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
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-01 20:21:28 -07:00
|
|
|
// 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)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-30 11:13:53 -07:00
|
|
|
const transferFrom = {
|
2021-08-01 20:21:28 -07:00
|
|
|
[CHAIN_ID_ETH]: transferFromEth,
|
|
|
|
[CHAIN_ID_SOLANA]: transferFromSolana
|
2021-07-30 11:13:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export default transferFrom
|