From 56b5049a218394c20ee6ab6770273c401113868e Mon Sep 17 00:00:00 2001 From: Sebastien La Duca Date: Sun, 12 Nov 2023 14:01:26 -0500 Subject: [PATCH] display gas estimate (#27) * display gas estimate * adjust formatting, convert decimals * changeset * make casing consistent * put others back * rename field `gasFeeEstimate` * shorten note text * Fix typo, PR feedback nit, unit test * fix test * prettier * fix field name * unlink * update deps * update to beta version * snap manifest * fix test --------- Co-authored-by: danielpark --- .changeset/moody-adults-sip.md | 5 ++ .changeset/pre.json | 10 ++++ CHANGELOG.md | 6 +++ package.json | 10 ++-- snap.manifest.json | 4 +- src/index.ts | 5 +- src/utils/display.ts | 54 +++++++++++++++++--- src/validation.ts | 1 + test/validation.ts | 1 + yarn.lock | 92 +++++++++++++++++++++++++--------- 10 files changed, 148 insertions(+), 40 deletions(-) create mode 100644 .changeset/moody-adults-sip.md create mode 100644 .changeset/pre.json diff --git a/.changeset/moody-adults-sip.md b/.changeset/moody-adults-sip.md new file mode 100644 index 0000000..bdf7ca6 --- /dev/null +++ b/.changeset/moody-adults-sip.md @@ -0,0 +1,5 @@ +--- +"@nocturne-xyz/snap": minor +--- + +display gas estimate to user diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000..9c5806d --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,10 @@ +{ + "mode": "pre", + "tag": "beta", + "initialVersions": { + "@nocturne-xyz/snap": "0.9.0" + }, + "changesets": [ + "moody-adults-sip" + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index c74a218..79b16bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.10.0-beta.0 + +### Minor Changes + +- c6385c2: display gas estimate to user + ## 0.9.0 ### Minor Changes diff --git a/package.json b/package.json index 766d2fc..71e7f2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nocturne-xyz/snap", - "version": "0.9.0", + "version": "0.10.0-beta.0", "description": "Nocturne Snap", "license": "(MIT-0 OR Apache-2.0)", "main": "src/index.ts", @@ -33,10 +33,10 @@ }, "dependencies": { "@metamask/snaps-ui": "^0.32.2", - "@nocturne-xyz/client": "^3.1.0", - "@nocturne-xyz/config": "^1.5.0", - "@nocturne-xyz/core": "^3.1.1", - "@nocturne-xyz/crypto": "^0.3.0", + "@nocturne-xyz/client": "^3.1.3-beta.0", + "@nocturne-xyz/config": "^1.7.0-beta.0", + "@nocturne-xyz/core": "^3.1.2-beta.0", + "@nocturne-xyz/crypto": "^0.4.0-beta.0", "bigint-json-serialization": "^1.0.1", "buffer": "^6.0.3", "superstruct": "^1.0.3" diff --git a/snap.manifest.json b/snap.manifest.json index 241549b..d221ad6 100644 --- a/snap.manifest.json +++ b/snap.manifest.json @@ -1,9 +1,9 @@ { - "version": "0.9.0", + "version": "0.10.0-beta.0", "description": "Nocturne Snap", "proposedName": "Nocturne Snap", "source": { - "shasum": "Y6Wk18P5pZ8BgZ+OH4QY2n7On0CtZAWt2iXTdFnXGck=", + "shasum": "1aG0NvMOKUwvVBc6pDwYJZPzbj7rdTevmE2pnJjxHW0=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/src/index.ts b/src/index.ts index b60ba1a..0bdde5a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import { } from "@nocturne-xyz/client"; import { loadNocturneConfigBuiltin } from "@nocturne-xyz/config"; import { + AssetTrait, NocturneSigner, computeCanonAddrRegistryEntryDigest, thunk, @@ -194,7 +195,9 @@ async function handleRpcRequest({ const { op, metadata } = request.params; const content = makeSignOperationContent( metadata ?? { items: [] }, - (await configThunk()).erc20s + (await configThunk()).erc20s, + AssetTrait.decode(op.encodedGasAsset).assetAddr, + op.gasFeeEstimate ); // Confirm spend sig auth const opConfirmRes = await snap.request({ diff --git a/src/utils/display.ts b/src/utils/display.ts index a07fbac..1919f43 100644 --- a/src/utils/display.ts +++ b/src/utils/display.ts @@ -30,10 +30,10 @@ const displayAmount = (amount: string | number): string => { const makeFinalContent = ( items: { heading: string; messages: string[] }[] ): Panel => { - const formattedItems = items.flatMap((item) => { + const formattedItems = items.flatMap((item, i) => { return [ + ...(i > 0 ? [divider()] : []), heading(item.heading), - divider(), ...item.messages.map((m) => { const safeText = m.replace(NEWLINE_AND_CARRIAGE_RETURN_REGEX, ""); // Strip newlines and carriage returns to avoid injected malicious formatting return text(safeText); @@ -58,9 +58,19 @@ export const makeSignCanonAddrRegistryEntryContent = ( export const makeSignOperationContent = ( opMetadata: OperationMetadata, - erc20s: Map + erc20s: Map, + gasAssetContractAddr: Address, + fee: bigint ): Panel => { - const items = opMetadata.items.map((item) => { + const headItem = { + heading: "Confirm transaction from your Nocturne account".replace( + NEWLINE_AND_CARRIAGE_RETURN_REGEX, + "" + ), + messages: [], + }; + + const actionItems = opMetadata.items.map((item) => { if (item.type !== "Action") throw new Error(`${item.type} snap display not yet supported`); @@ -79,7 +89,7 @@ export const makeSignOperationContent = ( const ticker = lookupTickerByAddress(erc20Address, erc20s); const displayAmount = formatUnits(amountSmallestUnits); - heading = "Confirm transfer from your Nocturne account"; + heading = "ERC-20 Transfer"; messages.push( "Action: Transfer", `Amount: **${displayAmount}**`, @@ -93,7 +103,7 @@ export const makeSignOperationContent = ( case "Transfer ETH": { const { recipientAddress, amount: amountSmallestUnits } = item; const displayAmountEth = formatUnits(amountSmallestUnits); - heading = "Confirm transfer from your Nocturne account"; + heading = "ETH Transfer"; messages.push( `Action: Send **${displayAmountEth} ETH**`, `Recipient Address: ${recipientAddress}` @@ -117,7 +127,7 @@ export const makeSignOperationContent = ( formatUnits(minimumAmountOutWei) ); const displaySlippage = displayAmount(maxSlippageBps / 100); - heading = "Confirm token swap"; + heading = "Token swap"; if (tickerIn && tickerOut) { messages.push( @@ -151,5 +161,33 @@ export const makeSignOperationContent = ( ), }; }); - return makeFinalContent(items); + + const gasItemHeader = "Gas Compensation"; + const gasItemMessages = []; + const gasAssetTicker = lookupTickerByAddress(gasAssetContractAddr, erc20s); + if (!gasAssetTicker) { + gasItemMessages.push( + `Gas Fee: **${formatUnits( + fee + )} of unrecognized token (${gasAssetContractAddr})**` + ); + } else { + const decimals = erc20s.get(gasAssetTicker)!.precision; + gasItemMessages.push( + `Gas Fee: **${formatUnits(fee, decimals)} ${gasAssetTicker}**` + ); + } + + gasItemMessages.push( + "Note: This fee is an estimate. Any excess will be refunded back to your Nocturne account." + ); + + const gasItem = { + heading: gasItemHeader, + messages: gasItemMessages.map((m) => + m.replace(NEWLINE_AND_CARRIAGE_RETURN_REGEX, "") + ), + }; + + return makeFinalContent([headItem, ...actionItems, gasItem]); }; diff --git a/src/validation.ts b/src/validation.ts index 665a903..957e51f 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -142,6 +142,7 @@ const PreSignOperationType = object({ deadline: bigint(), atomicActions: boolean(), joinSplits: array(PreSignJoinSplitType), + gasFeeEstimate: bigint(), }); const ConfidentialPaymentMetadataType = object({ diff --git a/test/validation.ts b/test/validation.ts index 7e5613e..845a84e 100644 --- a/test/validation.ts +++ b/test/validation.ts @@ -222,6 +222,7 @@ it("validates SignOperationParams", () => { }, }, ], + gasFeeEstimate: 1n, }, metadata: { items: [ diff --git a/yarn.lock b/yarn.lock index 6e692bb..fa1b379 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2769,49 +2769,60 @@ __metadata: languageName: node linkType: hard -"@nocturne-xyz/client@npm:^3.1.0": - version: 3.1.0 - resolution: "@nocturne-xyz/client@npm:3.1.0" +"@nocturne-xyz/client@npm:^3.1.3-beta.0": + version: 3.1.3-less-hashes + resolution: "@nocturne-xyz/client@npm:3.1.3-less-hashes" dependencies: "@nocturne-xyz/config": ^1.5.0 - "@nocturne-xyz/contracts": ^2.0.1 - "@nocturne-xyz/core": ^3.1.1 - "@nocturne-xyz/crypto": ^0.3.0 + "@nocturne-xyz/contracts": ^3.0.0 + "@nocturne-xyz/core": ^3.1.3-less-hashes + "@nocturne-xyz/crypto": ^0.4.0-less-hashes async-mutex: ^0.4.0 big-integer: ^1.6.42 bigint-json-serialization: ^1.0.1 ethers: ^5.7.2 js-sha256: ^0.9.0 - checksum: 081f1c3a9488970252a63d7d5712ee464c40ea81588652546f85b689618ef05a24afe1a479182f573c263ec0e8652d96029659dfbd3554b22e3917190b8c6ca4 + checksum: 3ddce7046a7cf774049c24de6b2e9f98955b0dd7e9305ae71ff88ee887c84f890cdefd89b2574e2b019f249e8e735ce2cb06a823b062a3d8c60a89082bf614e2 languageName: node linkType: hard "@nocturne-xyz/config@npm:^1.5.0": - version: 1.5.0 - resolution: "@nocturne-xyz/config@npm:1.5.0" + version: 1.6.0 + resolution: "@nocturne-xyz/config@npm:1.6.0" dependencies: big-integer: ^1.6.42 bigint-json-serialization: ^1.0.1 ethers: ^5.7.2 - checksum: 58da3e1b372765c2a47e07486744e052548352488de9df24992b794756cb86b4cd58ee6c1e9e146431f1e3a33bbb5a83ad056d37d8e7ccb78b1e489133103198 + checksum: 735997ae13f106b4aefb30df9564ead7ebd6292185b7740c516843441c14075eb2aa59f2bc3d79185ec994955e57f21ae5e4639c0e57aac75365a11fd1a9ffce languageName: node linkType: hard -"@nocturne-xyz/contracts@npm:^2.0.1": - version: 2.0.1 - resolution: "@nocturne-xyz/contracts@npm:2.0.1" +"@nocturne-xyz/config@npm:^1.7.0-beta.0": + version: 1.7.0-beta.0 + resolution: "@nocturne-xyz/config@npm:1.7.0-beta.0" + dependencies: + big-integer: ^1.6.42 + bigint-json-serialization: ^1.0.1 + ethers: ^5.7.2 + checksum: 3c8fa50a4cbe6b4c8109ac22e085ab25544cc759cb66e1f576c33598ec6ab99d477c60cad51e578fbab7b6f821580b4e5ea7702cc4fc6d2d56a6ec39c010aec7 + languageName: node + linkType: hard + +"@nocturne-xyz/contracts@npm:^3.0.0": + version: 3.0.0 + resolution: "@nocturne-xyz/contracts@npm:3.0.0" dependencies: "@openzeppelin/contracts": 4.9.2 "@openzeppelin/contracts-upgradeable": 4.9.2 - checksum: 7021031cf7e0f4af76f95b450c128ebf84a1a6b759c82198d9c0fe4fa486564644fb33839aca751e5ae577a5c33fc1a0e51867ecb3b05e600029e2a24346572d + checksum: 9f8d519a020f27ad4af0090d863c0c9c51125348aa51302a4dd4443fd173afd7cd089aaab18e5618a01fa907f92883dc657665e62d4d9e56217a079f43649c26 languageName: node linkType: hard -"@nocturne-xyz/core@npm:^3.1.1": - version: 3.1.1 - resolution: "@nocturne-xyz/core@npm:3.1.1" +"@nocturne-xyz/core@npm:^3.1.2-beta.0": + version: 3.1.2 + resolution: "@nocturne-xyz/core@npm:3.1.2" dependencies: - "@nocturne-xyz/contracts": ^2.0.1 + "@nocturne-xyz/contracts": ^3.0.0 "@nocturne-xyz/crypto": ^0.3.0 "@zk-kit/incremental-merkle-tree": ^1.0.0 async-mutex: ^0.4.0 @@ -2822,7 +2833,26 @@ __metadata: js-sha256: ^0.9.0 sorted-btree: ^1.8.1 winston: ^3.9.0 - checksum: d12a1a817002f67209438fa90c2502404651184709fc349a26bef8b7a94fa5447a6bd2c091c6a08060deed6a4317859a5e0cd2ef5374da0eb37e9081fe04e5a1 + checksum: 47891973e2a73f7247dc4673f20d8eb8ae0300e02082f48de61039f2b74ef2c1d2e5d32c7be0ff3040dbcc0a22a829080ad6138328672408971f9fcd4143b4ee + languageName: node + linkType: hard + +"@nocturne-xyz/core@npm:^3.1.3-less-hashes": + version: 3.1.3-tsup1 + resolution: "@nocturne-xyz/core@npm:3.1.3-tsup1" + dependencies: + "@nocturne-xyz/contracts": ^3.0.0 + "@nocturne-xyz/crypto": ^0.4.0-tsup1 + "@zk-kit/incremental-merkle-tree": ^1.1.0 + async-mutex: ^0.4.0 + async-retry: ^1.3.3 + big-integer: ^1.6.42 + bigint-json-serialization: ^1.0.1 + ethers: ^5.7.2 + js-sha256: ^0.9.0 + sorted-btree: ^1.8.1 + winston: ^3.9.0 + checksum: e8a1ef947a590fc6ec736c833e67d4b03333c1dedca42e6843963e99bae09a5fb88a77b4dd94b209a834892ec4782c9087e0813d608080ed7cd6f1c02030b3a8 languageName: node linkType: hard @@ -2839,6 +2869,20 @@ __metadata: languageName: node linkType: hard +"@nocturne-xyz/crypto@npm:^0.4.0-beta.0, @nocturne-xyz/crypto@npm:^0.4.0-less-hashes, @nocturne-xyz/crypto@npm:^0.4.0-tsup1": + version: 0.4.0-tsup1 + resolution: "@nocturne-xyz/crypto@npm:0.4.0-tsup1" + dependencies: + "@noble/curves": ^1.2.0 + "@noble/hashes": ^1.3.1 + "@stablelib/chacha20poly1305": ^1.0.1 + bigint-json-serialization: ^1.0.1 + ethers: ^5.7.2 + randombytes: ^2.1.0 + checksum: 3f301311a2553d48dd7457e18f52db648366de33200c27c4cb0c96b3e1c7dd39e2e5dda42b226e9d19ffd58c0a89eccdad219ce049e1e666776c619c6cf16538 + languageName: node + linkType: hard + "@nocturne-xyz/snap@workspace:.": version: 0.0.0-use.local resolution: "@nocturne-xyz/snap@workspace:." @@ -2853,10 +2897,10 @@ __metadata: "@metamask/snaps-cli": 0.32.2 "@metamask/snaps-types": 0.32.2 "@metamask/snaps-ui": ^0.32.2 - "@nocturne-xyz/client": ^3.1.0 - "@nocturne-xyz/config": ^1.5.0 - "@nocturne-xyz/core": ^3.1.1 - "@nocturne-xyz/crypto": ^0.3.0 + "@nocturne-xyz/client": ^3.1.3-beta.0 + "@nocturne-xyz/config": ^1.7.0-beta.0 + "@nocturne-xyz/core": ^3.1.2-beta.0 + "@nocturne-xyz/crypto": ^0.4.0-beta.0 "@types/chai": ^4.3.9 "@types/mocha": ^10.0.3 "@types/node": ^20.8.9 @@ -3423,7 +3467,7 @@ __metadata: languageName: node linkType: hard -"@zk-kit/incremental-merkle-tree@npm:^1.0.0": +"@zk-kit/incremental-merkle-tree@npm:^1.0.0, @zk-kit/incremental-merkle-tree@npm:^1.1.0": version: 1.1.0 resolution: "@zk-kit/incremental-merkle-tree@npm:1.1.0" checksum: 5f2d6dd2a4898aa75f72d5b3811ab965c369f0a51561250313849fb9a6a1163064c4887da3bea298d25e80a4bc79b3c6997edf6492a6a8fc157512bc3fcb5e23