Compare commits
3 Commits
bed5efbb89
...
30453c7953
Author | SHA1 | Date |
---|---|---|
Evan Gray | 30453c7953 | |
Evan Gray | 37ed1b9f58 | |
Evan Gray | b9d6177e6c |
21
README.md
21
README.md
|
@ -1,5 +1,24 @@
|
|||
# example-portal-fast-withdrawal
|
||||
# Example Portal Fast Withdrawal
|
||||
|
||||
In a world where Ethereum finality takes ~18 minutes and Wormhole offers instant, un-finalized messaging in addition to finalized messaging, this repo imagines a Portal which can offer even faster transfers.
|
||||
|
||||
_Gotta go fast!_
|
||||
|
||||
## Concept
|
||||
|
||||
Provide liquidity for fast withdrawals in exchange for fee emissions (at the risk of never receiving the Portal transfer due to rollbacks). If pooled funds exist on the target chain, the user can complete their transfer immediately. If not, they can complete their transfer after their portal funds arrive.
|
||||
|
||||
## Progress
|
||||
|
||||
- [x] Send fast transfer and portal transfer
|
||||
- [ ] Redeem fast transfer to user, sans 1% to pool / 1% to protocol
|
||||
- [ ] Redeem portal transfer to pool
|
||||
- [ ] Setup pool via creating and registering of LP token
|
||||
- [ ] Portal ABI parity
|
||||
- [ ] Ownable and owner-only registration
|
||||
- [ ] Specialized relayer to relay fast and portal transfers
|
||||
- [ ] Simple UI
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This is an example only, not suitable for practically anything!
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
/ethers-contracts/
|
||||
/lib/
|
||||
/node_modules/
|
||||
addresses.json
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
// SPDX-License-Identifier: Apache 2
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../contracts/FastTransfer.sol";
|
||||
import "forge-std/Test.sol";
|
||||
|
||||
contract TestFastTransfer is FastTransfer, Test {
|
||||
|
||||
function testWrapAndTransferETH() public {
|
||||
// Goerli Testnet
|
||||
wormhole = IWormhole(0x706abc4E45D419950511e474C7B9Ed348A4a716c);
|
||||
portal = ITokenBridge(0xF890982f9310df57d00f659cf4fd87e65adEd8d7);
|
||||
|
||||
// TODO: test
|
||||
|
||||
}
|
||||
}
|
18
evm/foundry
18
evm/foundry
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This script is a wrapper around the foundry Docker image.
|
||||
# In an ideal world, we could just use anvil (and forge) directly, but there are regular
|
||||
# upstream breaking changes in the nightly builds, and binaries of older
|
||||
# versions are deleted frequently from their GitHub. The Docker releases are
|
||||
# available for longer, so we just use those here.
|
||||
#
|
||||
# the DOCKER_ARGS environment variable can be used to pass additional args to docker.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
# This is a known-to-be-working build.
|
||||
DOCKER_IMAGE="ghcr.io/foundry-rs/foundry:nightly-0d4468765c264d00ac961275fe176ce003d3e4ca@sha256:88fe2ea1005b9a3a7f8068645fef4cfb0fa7c16a5dd3b35582c70a1e36d16c25"
|
||||
|
||||
args=$(printf '"%s" ' "$@")
|
||||
|
||||
docker run --rm --platform=linux/amd64 -i $DOCKER_ARGS $DOCKER_IMAGE "$args"
|
|
@ -4,11 +4,11 @@
|
|||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "DOCKER_ARGS=\"-v $(pwd):/app\" ./foundry sh -c \"cd app && forge test\"",
|
||||
"genTypes": "typechain --target ethers-v5 --out-dir ethers-contracts/abi --show-stack-traces ./build/contracts/*.json",
|
||||
"generate": "rimraf lib && rimraf ethers-contracts && rimraf build && truffle compile && npm run genTypes",
|
||||
"build": "truffle compile",
|
||||
"truffle": "truffle"
|
||||
"deploy-devnet": "truffle compile && truffle exec scripts/deploy_devnet.js --network development",
|
||||
"test-devnet": "node scripts/test_devnet.js",
|
||||
"deploy-testnet": "truffle compile && truffle exec scripts/deploy_testnet.js --network ethereum_testnet",
|
||||
"test-testnet": "node scripts/test_testnet.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
const FastTransfer = artifacts.require("FastTransfer");
|
||||
let addresses = {};
|
||||
try {
|
||||
addresses = require("../addresses.json");
|
||||
} catch (e) {}
|
||||
const { CONTRACTS } = require("@certusone/wormhole-sdk");
|
||||
const fs = require("fs");
|
||||
module.exports = async function (callback) {
|
||||
try {
|
||||
const ft = await FastTransfer.new(
|
||||
CONTRACTS.DEVNET.ethereum.core,
|
||||
CONTRACTS.DEVNET.ethereum.token_bridge
|
||||
);
|
||||
console.log("tx: " + ft.transactionHash);
|
||||
console.log("FastTransfer address: " + ft.address);
|
||||
addresses.devnet = ft.address;
|
||||
fs.writeFileSync("./addresses.json", JSON.stringify(addresses));
|
||||
callback();
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
const FastTransfer = artifacts.require("FastTransfer");
|
||||
let addresses = {};
|
||||
try {
|
||||
addresses = require("../addresses.json");
|
||||
} catch (e) {}
|
||||
const { CONTRACTS } = require("@certusone/wormhole-sdk");
|
||||
const fs = require("fs");
|
||||
module.exports = async function (callback) {
|
||||
try {
|
||||
const ft = await FastTransfer.new(
|
||||
CONTRACTS.TESTNET.ethereum.core,
|
||||
CONTRACTS.TESTNET.ethereum.token_bridge
|
||||
);
|
||||
console.log("tx: " + ft.transactionHash);
|
||||
console.log("FastTransfer address: " + ft.address);
|
||||
addresses.testnet = ft.address;
|
||||
fs.writeFileSync("./addresses.json", JSON.stringify(addresses));
|
||||
callback();
|
||||
} catch (e) {
|
||||
callback(e);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,55 @@
|
|||
const {
|
||||
CONTRACTS,
|
||||
CHAIN_ID_ETH,
|
||||
parseSequencesFromLogEth,
|
||||
transferFromEthNative,
|
||||
tryNativeToUint8Array,
|
||||
getSignedVAAWithRetry,
|
||||
getEmitterAddressEth,
|
||||
} = require("@certusone/wormhole-sdk");
|
||||
const {
|
||||
NodeHttpTransport,
|
||||
} = require("@improbable-eng/grpc-web-node-http-transport");
|
||||
const addresses = require("../addresses.json");
|
||||
const { ethers } = require("ethers");
|
||||
|
||||
(async () => {
|
||||
const provider = new ethers.providers.JsonRpcProvider(
|
||||
"http://localhost:8545"
|
||||
);
|
||||
const signer = new ethers.Wallet(process.env.MNEMONIC, provider);
|
||||
// the fast transfer contract shares the same interface with the token bridge
|
||||
const receipt = await transferFromEthNative(
|
||||
addresses.devnet,
|
||||
signer,
|
||||
ethers.utils.parseEther(".00000001"),
|
||||
4,
|
||||
tryNativeToUint8Array(await signer.getAddress(), CHAIN_ID_ETH),
|
||||
0
|
||||
);
|
||||
const [fastSeq, portalSeq] = parseSequencesFromLogEth(
|
||||
receipt,
|
||||
CONTRACTS.DEVNET.ethereum.core
|
||||
);
|
||||
console.log("fast seq", fastSeq, "portal seq", portalSeq);
|
||||
await getSignedVAAWithRetry(
|
||||
["http://localhost:7071"],
|
||||
CHAIN_ID_ETH,
|
||||
getEmitterAddressEth(addresses.devnet),
|
||||
fastSeq,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
console.log("fast", new Date().toISOString());
|
||||
await getSignedVAAWithRetry(
|
||||
["http://localhost:7071"],
|
||||
CHAIN_ID_ETH,
|
||||
getEmitterAddressEth(CONTRACTS.DEVNET.ethereum.token_bridge),
|
||||
portalSeq,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
console.log("portal", new Date().toISOString());
|
||||
})();
|
|
@ -0,0 +1,55 @@
|
|||
const {
|
||||
CONTRACTS,
|
||||
CHAIN_ID_ETH,
|
||||
parseSequencesFromLogEth,
|
||||
transferFromEthNative,
|
||||
tryNativeToUint8Array,
|
||||
getSignedVAAWithRetry,
|
||||
getEmitterAddressEth,
|
||||
} = require("@certusone/wormhole-sdk");
|
||||
const {
|
||||
NodeHttpTransport,
|
||||
} = require("@improbable-eng/grpc-web-node-http-transport");
|
||||
const addresses = require("../addresses.json");
|
||||
const { ethers } = require("ethers");
|
||||
|
||||
(async () => {
|
||||
const provider = new ethers.providers.JsonRpcProvider(
|
||||
"https://rpc.ankr.com/eth_goerli"
|
||||
);
|
||||
const signer = new ethers.Wallet(process.env.MNEMONIC, provider);
|
||||
// the fast transfer contract shares the same interface with the token bridge
|
||||
const receipt = await transferFromEthNative(
|
||||
addresses.testnet,
|
||||
signer,
|
||||
ethers.utils.parseEther(".00000001"),
|
||||
4,
|
||||
tryNativeToUint8Array(await signer.getAddress(), CHAIN_ID_ETH),
|
||||
0
|
||||
);
|
||||
const [fastSeq, portalSeq] = parseSequencesFromLogEth(
|
||||
receipt,
|
||||
CONTRACTS.TESTNET.ethereum.core
|
||||
);
|
||||
console.log("fast seq", fastSeq, "portal seq", portalSeq);
|
||||
await getSignedVAAWithRetry(
|
||||
["https://wormhole-v2-testnet-api.certus.one"],
|
||||
CHAIN_ID_ETH,
|
||||
getEmitterAddressEth(addresses.testnet),
|
||||
fastSeq,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
console.log("fast", new Date().toISOString());
|
||||
await getSignedVAAWithRetry(
|
||||
["https://wormhole-v2-testnet-api.certus.one"],
|
||||
CHAIN_ID_ETH,
|
||||
getEmitterAddressEth(CONTRACTS.TESTNET.ethereum.token_bridge),
|
||||
portalSeq,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
console.log("portal", new Date().toISOString());
|
||||
})();
|
Loading…
Reference in New Issue