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(bridge-ui): Recommend fee #457

Merged
merged 9 commits into from
Dec 21, 2022
6 changes: 4 additions & 2 deletions packages/bridge-ui/src/components/AddressDropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
import { fromChain } from "../store/chain";
import { truncateString } from "../utils/truncateString";

let address: string;
let addressAvatarImgData: string;
let address: string = "";
let addressAvatarImgData: string = "";
let tokenBalance: string = "";

onMount(async () => {
Expand All @@ -26,6 +26,8 @@

$: getUserBalance($signer);

$: setAddress($signer);

async function getUserBalance(signer) {
if (signer) {
const userBalance = await signer.getBalance("latest");
Expand Down
7 changes: 4 additions & 3 deletions packages/bridge-ui/src/components/form/BridgeForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
let requiresAllowance: boolean = true;
let btnDisabled: boolean = true;
let tokenBalance: string;
let customFee: string = "0.01";
let customFee: string = "0";
let recommendedFee: string = "0";
let memo: string = "";
let loading: boolean = false;

Expand Down Expand Up @@ -249,7 +250,7 @@
}

if ($processingFee === ProcessingFeeMethod.RECOMMENDED) {
return ethers.utils.parseEther("0.01");
return BigNumber.from(ethers.utils.parseEther(recommendedFee));
}
}
</script>
Expand Down Expand Up @@ -281,7 +282,7 @@
</label>
</div>

<ProcessingFee bind:customFee />
<ProcessingFee bind:customFee bind:recommendedFee />

<Memo bind:memo />

Expand Down
17 changes: 16 additions & 1 deletion packages/bridge-ui/src/components/form/ProcessingFee.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,23 @@
import { _ } from "svelte-i18n";
import { processingFee } from "../../store/fee";
import { ProcessingFeeMethod, PROCESSING_FEE_META } from "../../domain/fee";
import { toChain, fromChain } from "../../store/chain";
import { token } from "../../store/token";
import { signer } from "../../store/signer";
import { recommendProcessingFee } from "../../utils/recommendProcessingFee";

export let customFee: string;
export let recommendedFee: string = "0";

$: recommendProcessingFee(
$toChain,
$fromChain,
$processingFee,
$token,
$signer
)
.then((fee) => (recommendedFee = fee))
.catch((e) => console.error(e));

function selectProcessingFee(fee) {
$processingFee = fee;
Expand Down Expand Up @@ -45,7 +60,7 @@
</label>
{:else if $processingFee === ProcessingFeeMethod.RECOMMENDED}
<div class="flex items-left justify-between">
<span class="mt-2 text-sm">0.01 ETH </span>
<span class="mt-2 text-sm">{recommendedFee} ETH </span>
</div>
{/if}
</div>
2 changes: 2 additions & 0 deletions packages/bridge-ui/src/domain/proof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type GenerateProofOpts = {
signal: string;
sender: string;
srcBridgeAddress: string;
destChain: number;
destHeaderSyncAddress: string;
srcChain: number;
};

Expand Down
10 changes: 10 additions & 0 deletions packages/bridge-ui/src/erc20/bridge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ describe("bridge tests", () => {
bridge.Claim({
message: {
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand All @@ -272,6 +274,8 @@ describe("bridge tests", () => {
bridge.Claim({
message: {
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down Expand Up @@ -299,6 +303,8 @@ describe("bridge tests", () => {
message: {
owner: "0x",
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down Expand Up @@ -331,7 +337,9 @@ describe("bridge tests", () => {
message: {
owner: "0x",
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
sender: "0x01",
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down Expand Up @@ -365,7 +373,9 @@ describe("bridge tests", () => {
message: {
owner: "0x",
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
sender: "0x01",
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down
4 changes: 4 additions & 0 deletions packages/bridge-ui/src/erc20/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ERC20 from "../constants/abi/ERC20";
import type { Prover } from "../domain/proof";
import { MessageStatus } from "../domain/message";
import BridgeABI from "../constants/abi/Bridge";
import { chains } from "../domain/chain";

class ERC20Bridge implements Bridge {
private readonly prover: Prover;
Expand Down Expand Up @@ -145,6 +146,9 @@ class ERC20Bridge implements Bridge {
signal: opts.signal,
sender: opts.srcBridgeAddress,
srcBridgeAddress: opts.srcBridgeAddress,
destChain: opts.message.destChainId.toNumber(),
destHeaderSyncAddress:
chains[opts.message.destChainId.toNumber()].headerSyncAddress,
});

return await contract.processMessage(opts.message, proof, {
Expand Down
9 changes: 8 additions & 1 deletion packages/bridge-ui/src/eth/bridge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { mainnet, taiko } from "../domain/chain";
import type { Bridge, BridgeOpts } from "../domain/bridge";
import ETHBridge from "./bridge";
import { Message, MessageStatus } from "../domain/message";
import { src_url_equal } from "svelte/internal";

const mockSigner = {
getAddress: jest.fn(),
Expand Down Expand Up @@ -133,6 +132,8 @@ describe("bridge tests", () => {
bridge.Claim({
message: {
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down Expand Up @@ -160,6 +161,8 @@ describe("bridge tests", () => {
message: {
owner: "0x",
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
d1onys1us marked this conversation as resolved.
Show resolved Hide resolved
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down Expand Up @@ -192,7 +195,9 @@ describe("bridge tests", () => {
message: {
owner: "0x",
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
sender: "0x01",
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down Expand Up @@ -226,7 +231,9 @@ describe("bridge tests", () => {
message: {
owner: "0x",
srcChainId: BigNumber.from(167001),
destChainId: BigNumber.from(31336),
sender: "0x01",
gasLimit: BigNumber.from(1),
} as unknown as Message,
signal: "0x",
srcBridgeAddress: "0x",
Expand Down
14 changes: 10 additions & 4 deletions packages/bridge-ui/src/eth/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import TokenVault from "../constants/abi/TokenVault";
import type { Prover } from "../domain/proof";
import { MessageStatus } from "../domain/message";
import Bridge from "../constants/abi/Bridge";
import { chains } from "../domain/chain";

class ETHBridge implements BridgeInterface {
private readonly prover: Prover;
Expand Down Expand Up @@ -90,19 +91,24 @@ class ETHBridge implements BridgeInterface {
}

if (messageStatus === MessageStatus.New) {
const proof = await this.prover.GenerateProof({
const proofOpts = {
srcChain: opts.message.srcChainId.toNumber(),
signal: opts.signal,
sender: opts.srcBridgeAddress,
srcBridgeAddress: opts.srcBridgeAddress,
});
destChain: opts.message.destChainId.toNumber(),
destHeaderSyncAddress:
chains[opts.message.destChainId.toNumber()].headerSyncAddress,
};

const proof = await this.prover.GenerateProof(proofOpts);

return await contract.processMessage(opts.message, proof, {
gasLimit: 1500000,
gasLimit: opts.message.gasLimit.add(1000000),
});
} else {
return await contract.retryMessage(opts.message, {
gasLimit: 1500000,
gasLimit: opts.message.gasLimit.add(1000000),
});
}
}
Expand Down
51 changes: 28 additions & 23 deletions packages/bridge-ui/src/proof/service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ const mockProvider = {
send: jest.fn(),
};

const mockContract = {
getLatestSyncedHeader: jest.fn(),
};

jest.mock("ethers", () => ({
/* eslint-disable-next-line */
...(jest.requireActual("ethers") as object),
Contract: function () {
return mockContract;
},
}));

const block = {
parentHash:
"0xa7881266ca0a344c43cb24175d9dbd243b58d45d6ae6ad71310a273a3d1d3afb",
Expand Down Expand Up @@ -67,6 +79,13 @@ const expectedProof =
const expectedProofWithBaseFee =
"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000360a7881266ca0a344c43cb24175d9dbd243b58d45d6ae6ad71310a273a3d1d3afb1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347000000000000000000000000ea674fdde714fd979de3edf0f56aa9716b898ec8c0dcf937b3f6136dd70a1ad11cc57b040fd410f3c49a5146f20c732895a3cc217273ade6b6ed865a9975ac281da23b90b141a8b607d874d2cd95e65e81336f8e74bb61e381e9238a08b169580f3cbf9b8b79d7d5ee708d3e286103eb291dfd0800000000000400000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000020000000000000000000000000000000000000000000000000100000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000000007b00000000000000000000000000000000000000000000000000000000000002e0f5ba25df1e92e89a09e0b32063b81795f631100801158f5fa733f2ba26843bd0000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001265746865726d696e652d75732d7765737431000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022e1a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";

const srcChain = 167001;
const destChain = 31336;

const map = new Map<number, ethers.providers.JsonRpcProvider>();
map.set(srcChain, mockProvider as unknown as ethers.providers.JsonRpcProvider);
map.set(destChain, mockProvider as unknown as ethers.providers.JsonRpcProvider);

describe("prover tests", () => {
beforeEach(() => {
jest.resetAllMocks();
Expand All @@ -76,7 +95,7 @@ describe("prover tests", () => {
it("throws on invalid proof", async () => {
mockProvider.send.mockImplementation(
(method: string, params: unknown[]) => {
if (method === "eth_getBlockByNumber") {
if (method === "eth_getBlockByHash") {
return block;
}

Expand All @@ -86,13 +105,6 @@ describe("prover tests", () => {
}
);

const srcChain = 167001;
const map = new Map<number, ethers.providers.JsonRpcProvider>();
map.set(
srcChain,
mockProvider as unknown as ethers.providers.JsonRpcProvider
);

const prover: ProofService = new ProofService(map);

await expect(
Expand All @@ -101,14 +113,16 @@ describe("prover tests", () => {
sender: ethers.constants.AddressZero,
srcBridgeAddress: ethers.constants.AddressZero,
srcChain: srcChain,
destChain: destChain,
destHeaderSyncAddress: ethers.constants.AddressZero,
})
).rejects.toThrowError("invalid proof");
});

it("generates proof", async () => {
mockProvider.send.mockImplementation(
(method: string, params: unknown[]) => {
if (method === "eth_getBlockByNumber") {
if (method === "eth_getBlockByHash") {
return block;
}

Expand All @@ -118,28 +132,23 @@ describe("prover tests", () => {
}
);

const srcChain = 167001;
const map = new Map<number, ethers.providers.JsonRpcProvider>();
map.set(
srcChain,
mockProvider as unknown as ethers.providers.JsonRpcProvider
);

const prover: ProofService = new ProofService(map);

const proof = await prover.GenerateProof({
signal: ethers.constants.HashZero,
sender: ethers.constants.AddressZero,
srcBridgeAddress: ethers.constants.AddressZero,
srcChain: srcChain,
destChain: destChain,
destHeaderSyncAddress: ethers.constants.AddressZero,
});
expect(proof).toBe(expectedProof);
});

it("generates proof with baseFeePerGas set", async () => {
mockProvider.send.mockImplementation(
(method: string, params: unknown[]) => {
if (method === "eth_getBlockByNumber") {
if (method === "eth_getBlockByHash") {
return block;
}

Expand All @@ -150,12 +159,6 @@ describe("prover tests", () => {
);

block.baseFeePerGas = "1";
const srcChain = 167001;
const map = new Map<number, ethers.providers.JsonRpcProvider>();
map.set(
srcChain,
mockProvider as unknown as ethers.providers.JsonRpcProvider
);

const prover: ProofService = new ProofService(map);

Expand All @@ -164,6 +167,8 @@ describe("prover tests", () => {
sender: ethers.constants.AddressZero,
srcBridgeAddress: ethers.constants.AddressZero,
srcChain: srcChain,
destChain: destChain,
destHeaderSyncAddress: ethers.constants.AddressZero,
});
expect(proof).toBe(expectedProofWithBaseFee);
});
Expand Down
15 changes: 12 additions & 3 deletions packages/bridge-ui/src/proof/service.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ethers } from "ethers";
import { Contract, ethers } from "ethers";
import { RLP } from "ethers/lib/utils.js";
import HeaderSync from "../constants/abi/HeaderSync";
import type { Block, BlockHeader } from "../domain/block";
import type {
Prover,
Expand All @@ -24,8 +25,16 @@ class ProofService implements Prover {

const provider = this.providerMap.get(opts.srcChain);

const block: Block = await provider.send("eth_getBlockByNumber", [
"latest",
const contract = new Contract(
opts.destHeaderSyncAddress,
HeaderSync,
this.providerMap.get(opts.destChain)
);

const latestSyncedHeader = await contract.getLatestSyncedHeader();

const block: Block = await provider.send("eth_getBlockByHash", [
latestSyncedHeader,
false,
]);

Expand Down
Loading