From 0fa80f30aee3c58019592eaa4db52e084ae8f02e Mon Sep 17 00:00:00 2001 From: Danilo Tuler Date: Fri, 1 Sep 2023 17:59:54 -0300 Subject: [PATCH] Fix wallet initialization --- .changeset/eighty-buttons-perform.md | 5 + packages/wallet/__tests__/wallet.test.ts | 174 ++++++++++++++++++++--- packages/wallet/package.json | 3 +- packages/wallet/src/index.ts | 8 +- packages/wallet/src/wallet.ts | 28 ++-- 5 files changed, 177 insertions(+), 41 deletions(-) create mode 100644 .changeset/eighty-buttons-perform.md diff --git a/.changeset/eighty-buttons-perform.md b/.changeset/eighty-buttons-perform.md new file mode 100644 index 0000000..8a94a71 --- /dev/null +++ b/.changeset/eighty-buttons-perform.md @@ -0,0 +1,5 @@ +--- +"@deroll/wallet": patch +--- + +fix wallet initialization diff --git a/packages/wallet/__tests__/wallet.test.ts b/packages/wallet/__tests__/wallet.test.ts index c1fa9bb..1a0edd5 100644 --- a/packages/wallet/__tests__/wallet.test.ts +++ b/packages/wallet/__tests__/wallet.test.ts @@ -1,47 +1,179 @@ -import { beforeEach, describe, test } from "vitest"; +import { beforeEach, describe, expect, test } from "vitest"; +import { Address, encodePacked, zeroAddress } from "viem"; + +import { + createWallet, + isERC20Deposit, + isEtherDeposit, + parseEtherDeposit, +} from "../src"; +import { erc20PortalAddress, etherPortalAddress } from "../src/rollups"; describe("Wallet", () => { beforeEach(() => {}); + test("isEtherDeposit", () => { + expect( + isEtherDeposit({ + metadata: { + msg_sender: etherPortalAddress, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }, + payload: "0xdeadbeef", + }), + ).toBeTruthy(); + + expect( + isEtherDeposit({ + metadata: { + msg_sender: etherPortalAddress.toLowerCase() as Address, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }, + payload: "0xdeadbeef", + }), + ).toBeTruthy(); + + expect( + isEtherDeposit({ + metadata: { + msg_sender: erc20PortalAddress, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }, + payload: "0xdeadbeef", + }), + ).toBeFalsy(); + }); + + test("isERC20Deposit", () => { + expect( + isERC20Deposit({ + metadata: { + msg_sender: erc20PortalAddress, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }, + payload: "0xdeadbeef", + }), + ).toBeTruthy(); + + expect( + isERC20Deposit({ + metadata: { + msg_sender: erc20PortalAddress.toLowerCase() as Address, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }, + payload: "0xdeadbeef", + }), + ).toBeTruthy(); + + expect( + isERC20Deposit({ + metadata: { + msg_sender: etherPortalAddress, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }, + payload: "0xdeadbeef", + }), + ).toBeFalsy(); + }); + + test("parseEtherDeposit", () => { + const sender = "0x18930e8a66a1DbE21D00581216789AAB7460Afd0"; + const value = 123456n; + const payload = encodePacked(["address", "uint256"], [sender, value]); + const deposit = parseEtherDeposit(payload); + expect(deposit).toEqual({ + sender, + value, + }); + }); + test("init", () => {}); - test("deposit ETH", () => {}); + test("deposit ETH", async () => { + const wallet = createWallet(); + const sender = "0x18930e8a66a1DbE21D00581216789AAB7460Afd0"; + const value = 123456n; + const payload = encodePacked(["address", "uint256"], [sender, value]); + const metadata = { + msg_sender: etherPortalAddress, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }; + const response = await wallet.handler({ metadata, payload }); + expect(response).toEqual("accept"); + expect(wallet.balanceOf(sender)).toEqual(value); + }); - test("deposit ETH non normalized address", () => {}); + test("deposit ETH non normalized address", async () => { + const wallet = createWallet(); + const sender = "0x18930e8a66a1DbE21D00581216789AAB7460Afd0"; + const value = 123456n; + const payload = encodePacked(["address", "uint256"], [sender, value]); + const metadata = { + msg_sender: etherPortalAddress, + block_number: 0, + epoch_index: 0, + input_index: 0, + timestamp: 0, + }; + const response = await wallet.handler({ metadata, payload }); + expect(response).toEqual("accept"); + expect(wallet.balanceOf(sender.toLowerCase())).toEqual(value); + }); - test("deposit ERC20", () => {}); + test.todo("deposit ERC20", () => {}); - test("transfer ETH without balance", () => {}); + test.todo("transfer ETH without balance", () => {}); - test("transfer ETH", () => {}); + test.todo("transfer ETH", () => {}); - test("transfer ERC20 without balance", () => {}); + test.todo("transfer ERC20 without balance", () => {}); - test("transfer ERC20", () => {}); + test.todo("transfer ERC20", () => {}); - test("withdraw ETH with no balance", () => {}); + test.todo("withdraw ETH with no balance", () => {}); - test("withdraw ETH with undefined portal address", () => {}); + test.todo("withdraw ETH with undefined portal address", () => {}); - test("withdraw ETH", () => {}); + test.todo("withdraw ETH", () => {}); - test("withdraw ERC20", () => {}); + test.todo("withdraw ERC20", () => {}); - test("withdraw ERC20 with no balance", () => {}); + test.todo("withdraw ERC20 with no balance", () => {}); - test("depositEtherRoute reject", () => {}); + test.todo("depositEtherRoute reject", () => {}); - test("depositEtherRoute", () => {}); + test.todo("depositEtherRoute", () => {}); - test("depositERC20Route reject", () => {}); + test.todo("depositERC20Route reject", () => {}); - test("depositERC20Route", () => {}); + test.todo("depositERC20Route", () => {}); - test("withdrawEtherRoute reject no balance", async () => {}); + test.todo("withdrawEtherRoute reject no balance", async () => {}); - test("withdrawEtherRoute", async () => {}); + test.todo("withdrawEtherRoute", async () => {}); - test("withdrawERC20Route reject no balance", async () => {}); + test.todo("withdrawERC20Route reject no balance", async () => {}); - test("withdrawERC20Route", async () => {}); + test.todo("withdrawERC20Route", async () => {}); }); diff --git a/packages/wallet/package.json b/packages/wallet/package.json index 9534c0c..3b9f36a 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -16,7 +16,8 @@ "compile": "tsup", "dev": "tsup --watch", "lint": "eslint", - "prepack": "run-s build" + "prepack": "run-s build", + "test": "vitest" }, "dependencies": { "@deroll/app": "workspace:*", diff --git a/packages/wallet/src/index.ts b/packages/wallet/src/index.ts index 0cc5727..3cceca8 100644 --- a/packages/wallet/src/index.ts +++ b/packages/wallet/src/index.ts @@ -41,7 +41,8 @@ export type ERC20Deposit = { * @returns */ export const parseEtherDeposit = (payload: Payload): EtherDeposit => { - const sender = slice(payload, 0, 20); // 20 bytes for address + // normalize address, for safety + const sender = getAddress(slice(payload, 0, 20)); // 20 bytes for address const value = hexToBigInt(slice(payload, 20, 52), { size: 32 }); // 32 bytes for uint256 return { sender, value }; }; @@ -53,8 +54,9 @@ export const parseEtherDeposit = (payload: Payload): EtherDeposit => { */ export const parseERC20Deposit = (payload: Payload): ERC20Deposit => { const success = hexToBool(slice(payload, 0, 1)); // 1 byte for boolean - const token = slice(payload, 1, 21); // 20 bytes for address - const sender = slice(payload, 21, 41); // 20 bytes for address + // normalize addresses, for safety + const token = getAddress(slice(payload, 1, 21)); // 20 bytes for address + const sender = getAddress(slice(payload, 21, 41)); // 20 bytes for address const amount = hexToBigInt(slice(payload, 41, 73), { size: 32 }); // 32 bytes for uint256 return { success, token, sender, amount }; }; diff --git a/packages/wallet/src/wallet.ts b/packages/wallet/src/wallet.ts index cdfa444..c174e52 100644 --- a/packages/wallet/src/wallet.ts +++ b/packages/wallet/src/wallet.ts @@ -64,11 +64,7 @@ export class WalletAppImpl implements WalletApp { public handler: AdvanceRequestHandler = async (data) => { if (isEtherDeposit(data)) { let { sender, value } = parseEtherDeposit(data.payload); - - // normalize address, for safety - sender = getAddress(sender); - - const wallet = this.wallets[sender] ?? {}; + const wallet = this.wallets[sender] ?? { ether: 0n, erc20: {} }; wallet.ether += value; this.wallets[sender] = wallet; return "accept"; @@ -77,18 +73,18 @@ export class WalletAppImpl implements WalletApp { data.payload, ); - // normalize addresses, for safety - token = getAddress(token); - sender = getAddress(sender); - - const wallet = this.wallets[sender] ?? {}; - wallet.erc20[token] = wallet.erc20[token] - ? wallet.erc20[token] + amount - : amount; - this.wallets[sender] = wallet; + if (success) { + const wallet = this.wallets[sender] ?? { ether: 0n, erc20: {} }; + wallet.erc20[token] = wallet.erc20[token] + ? wallet.erc20[token] + amount + : amount; + this.wallets[sender] = wallet; + } return "accept"; - } else if (data.metadata.msg_sender === dAppAddressRelayAddress) { - this.dapp = data.payload; + } else if ( + getAddress(data.metadata.msg_sender) === dAppAddressRelayAddress + ) { + this.dapp = getAddress(data.payload); return "accept"; } return "reject";