Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bccc86b6ea |
@@ -3508,36 +3508,34 @@ Currently supported:
|
|||||||
the router take `Token In` (see below): a permit of 5,000 DAI to another
|
the router take `Token In` (see below): a permit of 5,000 DAI to another
|
||||||
address and then a V3 exact-in of 600 USDT read `Swap USDT → USDC` with
|
address and then a V3 exact-in of 600 USDT read `Swap USDT → USDC` with
|
||||||
`Amount 600.0000 USDT`, and so do that exact-in and then a permit of 5,000 DAI
|
`Amount 600.0000 USDT`, and so do that exact-in and then a permit of 5,000 DAI
|
||||||
to the router. A permit on the zero address never stands as the `Amount`
|
to the router. When a permit's amount stands and the step that sets the input
|
||||||
figure, because Permit2 has no allowance of ETH. When a permit's amount stands
|
side spends a token other than the permit's, or one the decoder does not know,
|
||||||
and the step that sets the input side spends a token other than the permit's,
|
that step's amount gets lines of its own, unless it states no amount and the
|
||||||
or one the decoder does not know, that step's amount gets lines of its own,
|
user pays it none of its input token. Each take the total does not count gives
|
||||||
unless it states no amount and the user pays it none of its input token. Each
|
three lines after the `Amount` line (after `Token In` when there is none): one
|
||||||
take the total does not count gives three lines after the `Amount` line (after
|
of a token other than `Token In`; one of `Token In` after an amount that is
|
||||||
`Token In` when there is none): one of a token other than `Token In`; one of
|
not a quantity (a V4 open delta, `ALREADY_PAID`, which keep their wording on
|
||||||
`Token In` after an amount that is not a quantity (a V4 open delta,
|
the `Amount` line, or no stated amount, as of a V4 exact-out step); and one
|
||||||
`ALREADY_PAID`, which keep their wording on the `Amount` line, or no stated
|
whose amount the decoder does not know. When there is no `Amount` line, each
|
||||||
amount, as of a V4 exact-out step); and one whose amount the decoder does not
|
take the total counts gets them too, so that every amount the decoder reads is
|
||||||
know. When there is no `Amount` line, each take the total counts gets them
|
shown: the amount the step that sets the input side states, when it is a
|
||||||
too, so that every amount the decoder reads is shown: the amount the step that
|
quantity and the user pays that step (a V2 or V3 step whose `payerIsUser` is
|
||||||
sets the input side states, when it is a quantity and the user pays that step
|
true, a V4 step the user pays some of its input token, or a `WRAP_ETH`, whose
|
||||||
(a V2 or V3 step whose `payerIsUser` is true, a V4 step the user pays some of
|
ETH comes from the transaction's value), and each later take of `Token In`
|
||||||
its input token, or a `WRAP_ETH`, whose ETH comes from the transaction's
|
added to it. A step that sets the input side and is paid from the router takes
|
||||||
value), and each later take of `Token In` added to it. A step that sets the
|
nothing from the user's wallet and gets none. A `PERMIT2_PERMIT` the decoder
|
||||||
input side and is paid from the router takes nothing from the user's wallet
|
cannot read, then V3 exact-ins of 600 USDT and 400 DAI paid by the user, give
|
||||||
and gets none. A `PERMIT2_PERMIT` the decoder cannot read, then V3 exact-ins
|
lines for both amounts. When the step that sets the input side states no
|
||||||
of 600 USDT and 400 DAI paid by the user, give lines for both amounts. When
|
amount, the user pays it some of its input token, and there is no `Amount`
|
||||||
the step that sets the input side states no amount, the user pays it some of
|
line, that step gets them too whenever another take's lines give a figure, or
|
||||||
its input token, and there is no `Amount` line, that step gets them too
|
a `PERMIT2_TRANSFER_FROM` of its token gives one, on the lines below or, into
|
||||||
whenever another take's lines give a figure, or a `PERMIT2_TRANSFER_FROM` of
|
the router, on its `Paid to` line, so that figure cannot read as all that
|
||||||
its token gives one, on the lines below or, into the router, on its `Paid to`
|
leaves. When it states no amount and the user pays it none of its input token,
|
||||||
line, so that figure cannot read as all that leaves. When it states no amount
|
as when the router pays it, that step takes none of that token from the user's
|
||||||
and the user pays it none of its input token, as when the router pays it, that
|
wallet and never gets them, with a permit or without. They come in step order,
|
||||||
step takes none of that token from the user's wallet and never gets them, with
|
except that the step that sets the input side comes first when it has them,
|
||||||
a permit or without. They come in step order, except that the step that sets
|
followed, when there is no `Amount` line, by the other takes the total counts:
|
||||||
the input side comes first when it has them, followed, when there is no
|
`Moved from the sender`, its amount, worded as the `Amount` line words one, or
|
||||||
`Amount` line, by the other takes the total counts: `Moved from the sender`,
|
|
||||||
its amount, worded as the `Amount` line words one, or
|
|
||||||
`Unknown (could not be decoded)` when the decoder does not know it;
|
`Unknown (could not be decoded)` when the decoder does not know it;
|
||||||
`Token moved`, giving the token's address as the `Token In` line does; and
|
`Token moved`, giving the token's address as the `Token In` line does; and
|
||||||
`Moved to`, which reads `The swap step that spends it`. A token the decoder
|
`Moved to`, which reads `The swap step that spends it`. A token the decoder
|
||||||
@@ -3570,32 +3568,30 @@ Currently supported:
|
|||||||
amount stands gives none: the `Amount` line gives its amount, `Token In` its
|
amount stands gives none: the `Amount` line gives its amount, `Token In` its
|
||||||
token, and its spender is the router. Each allowance a `PERMIT2_PERMIT_BATCH`
|
token, and its spender is the router. Each allowance a `PERMIT2_PERMIT_BATCH`
|
||||||
grants, one for each token it names, all for its one spender, gives the same
|
grants, one for each token it names, all for its one spender, gives the same
|
||||||
three lines, in step order with those of each `PERMIT2_PERMIT`. For an
|
three lines, in step order with those of each `PERMIT2_PERMIT`. A
|
||||||
allowance of the zero address, `Permit2 allowance` gives the amount in base
|
`PERMIT2_PERMIT` or `PERMIT2_PERMIT_BATCH` whose input the decoder cannot
|
||||||
units and `Allowance token` gives the zero address. A `PERMIT2_PERMIT` or
|
read, such as one whose token or spender word has a nonzero top byte, may let
|
||||||
`PERMIT2_PERMIT_BATCH` whose input the decoder cannot read, such as one whose
|
any spender take any amount of any token: it gives one `Permit2 allowance`
|
||||||
token or spender word has a nonzero top byte, may let any spender take any
|
line alone, reading `Unknown (could not be decoded)`. These lines change no
|
||||||
amount of any token: it gives one `Permit2 allowance` line alone, reading
|
`Paid to` line: a permit or batch pays nobody. But code that a step runs, such
|
||||||
`Unknown (could not be decoded)`. These lines change no `Paid to` line: a
|
as a V4 pool's hook or a token's own code, can call a spender other than the
|
||||||
permit or batch pays nobody. But code that a step runs, such as a V4 pool's
|
router, which can then take up to its allowance from the user's wallet before
|
||||||
hook or a token's own code, can call a spender other than the router, which
|
the transaction ends. So an allowance to any spender but the router, or a
|
||||||
can then take up to its allowance from the user's wallet before the
|
permit or batch the decoder cannot read, makes the minimum read
|
||||||
transaction ends. So an allowance to any spender but the router, or a permit
|
`Min. paid out`, and when its token is `Token In`, or the decoder does not
|
||||||
or batch the decoder cannot read, makes the minimum read `Min. paid out`, and
|
know its token or `Token In`, it leaves no `Amount` line, whose figure might
|
||||||
when its token is `Token In`, or the decoder does not know its token or
|
be too low: a permit of 5,000 USDT to another address and then a V3 exact-in
|
||||||
`Token In`, it leaves no `Amount` line, whose figure might be too low: a
|
of 600 USDT read with no `Amount` line, and the 600 USDT gets lines of its
|
||||||
permit of 5,000 USDT to another address and then a V3 exact-in of 600 USDT
|
own. A step goes unread when its recipient does not decode as an address, when
|
||||||
read with no `Amount` line, and the 600 USDT gets lines of its own. A step
|
it is a V3 swap step whose path is shorter than one token address or has bytes
|
||||||
goes unread when its recipient does not decode as an address, when it is a V3
|
after its last hop, or when it is a command the decoder does not read: every
|
||||||
swap step whose path is shorter than one token address or has bytes after its
|
command other than `PERMIT2_PERMIT`, `PERMIT2_PERMIT_BATCH`,
|
||||||
last hop, or when it is a command the decoder does not read: every command
|
`PERMIT2_TRANSFER_FROM`, `V2_SWAP_EXACT_IN`, `V2_SWAP_EXACT_OUT`,
|
||||||
other than `PERMIT2_PERMIT`, `PERMIT2_PERMIT_BATCH`, `PERMIT2_TRANSFER_FROM`,
|
`V3_SWAP_EXACT_IN`, `V3_SWAP_EXACT_OUT`, `V4_SWAP`, `SWEEP`, `TRANSFER`,
|
||||||
`V2_SWAP_EXACT_IN`, `V2_SWAP_EXACT_OUT`, `V3_SWAP_EXACT_IN`,
|
`PAY_PORTION`, `PAY_PORTION_FULL_PRECISION`, `ACROSS_V4_DEPOSIT_V3`,
|
||||||
`V3_SWAP_EXACT_OUT`, `V4_SWAP`, `SWEEP`, `TRANSFER`, `PAY_PORTION`,
|
`WRAP_ETH`, `UNWRAP_WETH` and `BALANCE_CHECK_ERC20`
|
||||||
`PAY_PORTION_FULL_PRECISION`, `ACROSS_V4_DEPOSIT_V3`, `WRAP_ETH`,
|
(`PERMIT2_TRANSFER_FROM_BATCH`, `EXECUTE_SUB_PLAN` and the NFT commands among
|
||||||
`UNWRAP_WETH` and `BALANCE_CHECK_ERC20` (`PERMIT2_TRANSFER_FROM_BATCH`,
|
them), or a type its release names no command for.
|
||||||
`EXECUTE_SUB_PLAN` and the NFT commands among them), or a type its release
|
|
||||||
names no command for.
|
|
||||||
|
|
||||||
### Non-Goals Forever
|
### Non-Goals Forever
|
||||||
|
|
||||||
|
|||||||
@@ -44,12 +44,6 @@ let ctx;
|
|||||||
let versionClickCount = 0;
|
let versionClickCount = 0;
|
||||||
let versionClickTimer = null;
|
let versionClickTimer = null;
|
||||||
|
|
||||||
// The network Settings was last drawn for. A follow of a switch saved elsewhere
|
|
||||||
// sets `state` to the new network first. Settings is drawn again only once the
|
|
||||||
// follow's write returns. So both "Save" buttons take this network, not the one
|
|
||||||
// in `state`.
|
|
||||||
let shownNetwork = null;
|
|
||||||
|
|
||||||
// One row per site origin, however many addresses it appears under, each with
|
// One row per site origin, however many addresses it appears under, each with
|
||||||
// an [x] that hands it to onRemove.
|
// an [x] that hands it to onRemove.
|
||||||
function renderSiteList(containerId, origins, onRemove) {
|
function renderSiteList(containerId, origins, onRemove) {
|
||||||
@@ -205,7 +199,6 @@ function renderWalletListSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
shownNetwork = currentNetwork();
|
|
||||||
$("settings-rpc").value = state.rpcUrl;
|
$("settings-rpc").value = state.rpcUrl;
|
||||||
$("settings-blockscout").value = state.blockscoutUrl;
|
$("settings-blockscout").value = state.blockscoutUrl;
|
||||||
$("settings-network").value = state.networkId;
|
$("settings-network").value = state.networkId;
|
||||||
@@ -313,7 +306,6 @@ function showNewSettings() {
|
|||||||
state.checkRecipientsOnEtherscan;
|
state.checkRecipientsOnEtherscan;
|
||||||
if (state.currentView === "settings") {
|
if (state.currentView === "settings") {
|
||||||
markViewRendered("settings");
|
markViewRendered("settings");
|
||||||
shownNetwork = currentNetwork();
|
|
||||||
$("settings-network").value = state.networkId;
|
$("settings-network").value = state.networkId;
|
||||||
$("settings-rpc").value = state.rpcUrl;
|
$("settings-rpc").value = state.rpcUrl;
|
||||||
$("settings-blockscout").value = state.blockscoutUrl;
|
$("settings-blockscout").value = state.blockscoutUrl;
|
||||||
@@ -328,9 +320,9 @@ function showNewSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Saves `url` as `field` ("rpcUrl" or "blockscoutUrl") of the network
|
// Saves `url` as `field` ("rpcUrl" or "blockscoutUrl") of the network
|
||||||
// `networkId`, the one Settings showed when the user tapped "Save". The URL is
|
// `networkId`, the one active when the user tapped "Save". The URL is set in
|
||||||
// set in `state` inside the save, holding the lock. So the page cannot follow a
|
// `state` inside the save, holding the lock. So the page cannot follow a switch
|
||||||
// switch saved elsewhere (followStoredSettings() in src/popup/index.js) between
|
// saved elsewhere (followStoredSettings() in src/popup/index.js) between
|
||||||
// setting the URL and writing it. If the active network is no longer
|
// setting the URL and writing it. If the active network is no longer
|
||||||
// `networkId`, on this page or in the stored record, nothing is saved. The
|
// `networkId`, on this page or in the stored record, nothing is saved. The
|
||||||
// flash message then says that the network changed.
|
// flash message then says that the network changed.
|
||||||
@@ -360,8 +352,8 @@ function init(_ctx) {
|
|||||||
showFlash("Please enter an RPC URL.");
|
showFlash("Please enter an RPC URL.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The URL is for the network Settings shows when "Save" is tapped.
|
// The URL is for the network active when "Save" is tapped.
|
||||||
const net = shownNetwork;
|
const net = currentNetwork();
|
||||||
showFlash("Testing endpoint...");
|
showFlash("Testing endpoint...");
|
||||||
try {
|
try {
|
||||||
const resp = await debugFetch(url, {
|
const resp = await debugFetch(url, {
|
||||||
@@ -404,7 +396,7 @@ function init(_ctx) {
|
|||||||
showFlash("Please enter a Blockscout API URL.");
|
showFlash("Please enter a Blockscout API URL.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const net = shownNetwork;
|
const networkId = state.networkId;
|
||||||
showFlash("Testing endpoint...");
|
showFlash("Testing endpoint...");
|
||||||
try {
|
try {
|
||||||
const resp = await debugFetch(url + "/stats");
|
const resp = await debugFetch(url + "/stats");
|
||||||
@@ -419,7 +411,7 @@ function init(_ctx) {
|
|||||||
showFlash("Could not reach endpoint.");
|
showFlash("Could not reach endpoint.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await saveEndpoint("blockscoutUrl", url, net.id);
|
await saveEndpoint("blockscoutUrl", url, networkId);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Each change is made inside the save, holding the lock. So
|
// Each change is made inside the save, holding the lock. So
|
||||||
|
|||||||
+21
-47
@@ -2032,14 +2032,12 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// it may take more. A later permit or batch, or a later step this
|
// it may take more. A later permit or batch, or a later step this
|
||||||
// decoder did not read, may raise what Permit2 lets the router take.
|
// decoder did not read, may raise what Permit2 lets the router take.
|
||||||
// Every other PERMIT2_PERMIT leaves Token In and the Amount line as
|
// Every other PERMIT2_PERMIT leaves Token In and the Amount line as
|
||||||
// they read with no permit, and gets lines of its own below. A permit
|
// they read with no permit, and gets lines of its own below. A step
|
||||||
// on the zero address never stands as the Amount figure, because
|
// that may take from the sender what this decoder did not read leaves
|
||||||
// Permit2 has no allowance of ETH. A step that may take from the
|
// no figure, permit or not (see spentUnread()), and so do a permit
|
||||||
// sender what this decoder did not read leaves no figure, permit or
|
// or batch whose input it cannot read (see permitUnread()) and an
|
||||||
// not (see spentUnread()), and so do a permit or batch whose input it
|
// allowance of Token In to another spender (see toAnotherSpender). An
|
||||||
// cannot read (see permitUnread()) and an allowance of Token In to
|
// EXECUTE_SUB_PLAN step leaves both sides unknown (below).
|
||||||
// another spender (see toAnotherSpender). An EXECUTE_SUB_PLAN step
|
|
||||||
// leaves both sides unknown (below).
|
|
||||||
const stepCommands = Array.from(
|
const stepCommands = Array.from(
|
||||||
commandsBytes,
|
commandsBytes,
|
||||||
(b) => commands[b & commandTypeMask],
|
(b) => commands[b & commandTypeMask],
|
||||||
@@ -2049,7 +2047,6 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
stepCommands.filter((c) => c === "PERMIT2_PERMIT").length === 1 &&
|
stepCommands.filter((c) => c === "PERMIT2_PERMIT").length === 1 &&
|
||||||
!stepCommands.includes("PERMIT2_PERMIT_BATCH") &&
|
!stepCommands.includes("PERMIT2_PERMIT_BATCH") &&
|
||||||
sameAddress(permit.spender, toAddress) &&
|
sameAddress(permit.spender, toAddress) &&
|
||||||
permit.token !== "0x0000000000000000000000000000000000000000" &&
|
|
||||||
!permit.allowedToFail &&
|
!permit.allowedToFail &&
|
||||||
permit.beforeEveryTake &&
|
permit.beforeEveryTake &&
|
||||||
!stepsUnread.some((step) => step > permit.step);
|
!stepsUnread.some((step) => step > permit.step);
|
||||||
@@ -2237,19 +2234,17 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
// A null token in `spentFromSender`, a step this decoder did not read
|
// A null token in `spentFromSender`, a step this decoder did not read
|
||||||
// or a token it does not know, and an allowance to another spender
|
// or a token it does not know, and an allowance to another spender
|
||||||
// that may be of Token In, leave no Amount figure, which may then be
|
// that may be of Token In, leave no Amount figure, which may then be
|
||||||
// too low. An allowance of the zero address is never one of Token In,
|
// too low. With no Amount line, each take the total adds up gets
|
||||||
// because Permit2 has no allowance of ETH. With no Amount line, each
|
// lines of its own, first, so that every amount this decoder read is
|
||||||
// take the total adds up gets lines of its own, first, so that every
|
// shown.
|
||||||
// amount this decoder read is shown.
|
|
||||||
if (
|
if (
|
||||||
present(inputAmount) &&
|
present(inputAmount) &&
|
||||||
spentFromSender.every((s) => present(s.token)) &&
|
spentFromSender.every((s) => present(s.token)) &&
|
||||||
toAnotherSpender.every(
|
toAnotherSpender.every(
|
||||||
(p) =>
|
(p) =>
|
||||||
p.token === "0x0000000000000000000000000000000000000000" ||
|
present(p.token) &&
|
||||||
(present(p.token) &&
|
present(inputToken) &&
|
||||||
present(inputToken) &&
|
!sameAddress(p.token, inputToken),
|
||||||
!sameAddress(p.token, inputToken)),
|
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const amount = spentText(inputAmount, inInfo);
|
const amount = spentText(inputAmount, inInfo);
|
||||||
@@ -2320,36 +2315,15 @@ function decode(data, toAddress, chainId, sources, fromAddress) {
|
|||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Permit2 has no allowance of ETH. An allowance of the zero
|
details.push({
|
||||||
// address reads as one of a token nothing knows: its amount in
|
label: "Permit2 allowance",
|
||||||
// base units, and the zero address as its token.
|
value:
|
||||||
if (p.token === "0x0000000000000000000000000000000000000000") {
|
p.amount >= MAX_UINT160
|
||||||
details.push({
|
? "Unlimited"
|
||||||
label: "Permit2 allowance",
|
: amountText(p.amount, tokenInfo(p.token, sources))
|
||||||
value:
|
.display,
|
||||||
p.amount >= MAX_UINT160
|
});
|
||||||
? "Unlimited"
|
details.push(tokenMovedLine("Allowance token", p.token, sources));
|
||||||
: unknownDecimalsAmount(p.amount),
|
|
||||||
});
|
|
||||||
details.push({
|
|
||||||
label: "Allowance token",
|
|
||||||
value: p.token,
|
|
||||||
address: p.token,
|
|
||||||
isToken: true,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
details.push({
|
|
||||||
label: "Permit2 allowance",
|
|
||||||
value:
|
|
||||||
p.amount >= MAX_UINT160
|
|
||||||
? "Unlimited"
|
|
||||||
: amountText(p.amount, tokenInfo(p.token, sources))
|
|
||||||
.display,
|
|
||||||
});
|
|
||||||
details.push(
|
|
||||||
tokenMovedLine("Allowance token", p.token, sources),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
details.push({
|
details.push({
|
||||||
label: "Allowance spender",
|
label: "Allowance spender",
|
||||||
value: p.spender,
|
value: p.spender,
|
||||||
|
|||||||
@@ -319,90 +319,6 @@ test.each([
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// The popup's follow of the background's switch to Sepolia has set `state` to
|
|
||||||
// Sepolia. The follow's write has not returned yet, so Settings still shows
|
|
||||||
// Ethereum Mainnet. The user taps "Save" there. The URL is for Ethereum
|
|
||||||
// Mainnet, so the save stores the URL for neither network.
|
|
||||||
test.each([
|
|
||||||
{ button: "btn-save-rpc", field: "settings-rpc" },
|
|
||||||
{ button: "btn-save-blockscout", field: "settings-blockscout" },
|
|
||||||
])(
|
|
||||||
"$button saves nothing when tapped while the follow's write waits",
|
|
||||||
async ({ button, field }) => {
|
|
||||||
const page = await bootOnAddress();
|
|
||||||
await page.click("btn-settings");
|
|
||||||
// This answer passes both endpoint checks on Ethereum Mainnet.
|
|
||||||
globalThis.fetch.mockResolvedValue({
|
|
||||||
ok: true,
|
|
||||||
json: async () => ({ result: NETWORKS.mainnet.chainId }),
|
|
||||||
});
|
|
||||||
const url = "https://own-node.example.invalid";
|
|
||||||
|
|
||||||
const { set } = page.storage.local;
|
|
||||||
const write = set.getMockImplementation();
|
|
||||||
let releaseWrite;
|
|
||||||
const writeHeld = new Promise((resolve) => {
|
|
||||||
releaseWrite = resolve;
|
|
||||||
});
|
|
||||||
// The background's write lands; the next, the follow's, waits.
|
|
||||||
set.mockImplementationOnce(write).mockImplementationOnce(
|
|
||||||
async (items) => {
|
|
||||||
await writeHeld;
|
|
||||||
await write(items);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
await backgroundSwitch(page, "sepolia");
|
|
||||||
const { state } = require("../src/shared/state");
|
|
||||||
expect(state.networkId).toBe("sepolia");
|
|
||||||
expect(page.value("settings-network")).toBe("mainnet");
|
|
||||||
|
|
||||||
page.node(field).value = url;
|
|
||||||
const saving = page.node(button).listeners.click.map((fn) => fn());
|
|
||||||
await page.settle();
|
|
||||||
releaseWrite();
|
|
||||||
await Promise.all(saving);
|
|
||||||
await page.settle();
|
|
||||||
|
|
||||||
expect(JSON.stringify(page.storage.read("autistmask"))).not.toContain(
|
|
||||||
url,
|
|
||||||
);
|
|
||||||
expect(page.text("flash-msg")).toBe(
|
|
||||||
"The URL was not saved because the network changed.",
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// The user taps the RPC "Save" on Ethereum Mainnet. While the check waits for
|
|
||||||
// the node's answer, the popup follows the background's switch to Sepolia. The
|
|
||||||
// node answers with Sepolia's chain id. So the check refuses the node for
|
|
||||||
// Ethereum Mainnet, and nothing is stored.
|
|
||||||
test("the RPC check compares the answer with the network at the tap", async () => {
|
|
||||||
const page = await bootOnAddress();
|
|
||||||
await page.click("btn-settings");
|
|
||||||
let answer;
|
|
||||||
globalThis.fetch.mockReturnValue(
|
|
||||||
new Promise((resolve) => {
|
|
||||||
answer = resolve;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
const url = "https://sepolia-node.example.invalid";
|
|
||||||
|
|
||||||
page.node("settings-rpc").value = url;
|
|
||||||
const saving = page.node("btn-save-rpc").listeners.click.map((fn) => fn());
|
|
||||||
await page.settle();
|
|
||||||
await backgroundSwitch(page, "sepolia");
|
|
||||||
const { state } = require("../src/shared/state");
|
|
||||||
expect(state.networkId).toBe("sepolia");
|
|
||||||
answer({ json: async () => ({ result: NETWORKS.sepolia.chainId }) });
|
|
||||||
await Promise.all(saving);
|
|
||||||
await page.settle();
|
|
||||||
|
|
||||||
expect(JSON.stringify(page.storage.read("autistmask"))).not.toContain(url);
|
|
||||||
expect(page.text("flash-msg")).toBe(
|
|
||||||
"Wrong network: expected Ethereum Mainnet.",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Such as one a newer build wrote, which this build cannot read. Nothing reads
|
// Such as one a newer build wrote, which this build cannot read. Nothing reads
|
||||||
// or writes the stored record for it: the popup's next save finds it, as
|
// or writes the stored record for it: the popup's next save finds it, as
|
||||||
// before.
|
// before.
|
||||||
|
|||||||
@@ -3310,135 +3310,6 @@ describe("uniswap decoder", () => {
|
|||||||
|
|
||||||
expect(detail(result, "Amount").value).toBe("Up to 1000.0000 USDT");
|
expect(detail(result, "Amount").value).toBe("Up to 1000.0000 USDT");
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://git.eeqj.de/sneak/AutistMask/issues/660 — Permit2 has no
|
|
||||||
// allowance of ETH, so a permit on the zero address reads as one on a
|
|
||||||
// token nothing knows. On next at 53551c6 such a permit's Allowance
|
|
||||||
// token line read ETH. A permit of 1 wei of the zero address before a
|
|
||||||
// V4 step of 5 ETH made the Amount line read 0.000000000000000001 ETH.
|
|
||||||
// With that permit to another spender and a SETTLE the router pays, no
|
|
||||||
// line gave the 5 ETH.
|
|
||||||
describe("a permit on the zero address", () => {
|
|
||||||
const FIVE_ETH = 5000000000000000000n;
|
|
||||||
// The lines of a permit of `amount` base units of the zero
|
|
||||||
// address for `spender`.
|
|
||||||
const zeroAddressLines = (amount, spender) => [
|
|
||||||
[
|
|
||||||
"Permit2 allowance",
|
|
||||||
amount + " base units (decimals unknown)",
|
|
||||||
],
|
|
||||||
["Allowance token", ZERO_ADDR],
|
|
||||||
["Allowance spender", getAddress(spender)],
|
|
||||||
];
|
|
||||||
// A V4 swap of 5 ETH for USDC. The user pays its SETTLE when
|
|
||||||
// `payerIsUser` is true; otherwise the router pays it from the
|
|
||||||
// transaction's value.
|
|
||||||
const v4FiveEth = (payerIsUser) =>
|
|
||||||
encodeV4Swap(
|
|
||||||
new Uint8Array([
|
|
||||||
V4_SWAP_EXACT_IN_SINGLE_ID,
|
|
||||||
V4_SETTLE_ID,
|
|
||||||
V4_TAKE_ALL_ID,
|
|
||||||
]),
|
|
||||||
[
|
|
||||||
encodeV4ExactInSingle(
|
|
||||||
ZERO_ADDR,
|
|
||||||
USDC_ADDR,
|
|
||||||
FIVE_ETH,
|
|
||||||
1n,
|
|
||||||
),
|
|
||||||
settle(ZERO_ADDR, FIVE_ETH, payerIsUser),
|
|
||||||
encodeV4TakeAll(USDC_ADDR, 1n),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
test("a PERMIT2_PERMIT on the zero address names the address", () => {
|
|
||||||
const result = decodeSteps(
|
|
||||||
[0x00, 0x0a],
|
|
||||||
[
|
|
||||||
V3_600,
|
|
||||||
encodePermit2(
|
|
||||||
ZERO_ADDR,
|
|
||||||
1000000000000000000n,
|
|
||||||
ROUTER_ADDR,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
expect(linesBetweenTokens(result)).toEqual([
|
|
||||||
["Amount", "600.0000 USDT"],
|
|
||||||
...zeroAddressLines("1000000000000000000", ROUTER_ADDR),
|
|
||||||
]);
|
|
||||||
expect(detail(result, "Allowance token").address).toBe(
|
|
||||||
ZERO_ADDR,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("a PERMIT2_PERMIT_BATCH entry on the zero address names the address", () => {
|
|
||||||
const result = decodeSteps(
|
|
||||||
[0x03, 0x00],
|
|
||||||
[
|
|
||||||
encodePermit2Batch(
|
|
||||||
[
|
|
||||||
[USDT_ADDR, USDT_600],
|
|
||||||
[ZERO_ADDR, 1000000000000000000n],
|
|
||||||
],
|
|
||||||
ROUTER_ADDR,
|
|
||||||
),
|
|
||||||
V3_600,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
expect(linesBetweenTokens(result)).toEqual([
|
|
||||||
["Amount", "600.0000 USDT"],
|
|
||||||
...USDT_600_LINES,
|
|
||||||
...zeroAddressLines("1000000000000000000", ROUTER_ADDR),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("a PERMIT2_PERMIT of 1 wei of the zero address, then a V4 step of 5 ETH the user settles, shows the 5 ETH", () => {
|
|
||||||
const result = decodeSteps(
|
|
||||||
[0x0a, 0x10],
|
|
||||||
[
|
|
||||||
encodePermit2(ZERO_ADDR, 1n, ROUTER_ADDR),
|
|
||||||
v4FiveEth(true),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
expect(detail(result, "Token In").value).toBe("ETH (native)");
|
|
||||||
expect(linesBetweenTokens(result)).toEqual([
|
|
||||||
["Amount", "5.0000 ETH"],
|
|
||||||
...zeroAddressLines("1", ROUTER_ADDR),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("a PERMIT2_PERMIT of 1 wei of the zero address to another spender, then a V4 step of 5 ETH the router settles, shows the 5 ETH", () => {
|
|
||||||
const result = decodeSteps(
|
|
||||||
[0x0a, 0x10],
|
|
||||||
[
|
|
||||||
encodePermit2(ZERO_ADDR, 1n, OTHER_ADDR),
|
|
||||||
v4FiveEth(false),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
expect(detail(result, "Token In").value).toBe("ETH (native)");
|
|
||||||
expect(linesBetweenTokens(result)).toEqual([
|
|
||||||
["Amount", "5.0000 ETH"],
|
|
||||||
...zeroAddressLines("1", OTHER_ADDR),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("a PERMIT2_PERMIT_BATCH entry of 1 wei of the zero address to another spender, then a V4 step of 5 ETH the router settles, shows the 5 ETH", () => {
|
|
||||||
const result = decodeSteps(
|
|
||||||
[0x03, 0x10],
|
|
||||||
[
|
|
||||||
encodePermit2Batch([[ZERO_ADDR, 1n]], OTHER_ADDR),
|
|
||||||
v4FiveEth(false),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
expect(detail(result, "Token In").value).toBe("ETH (native)");
|
|
||||||
expect(linesBetweenTokens(result)).toEqual([
|
|
||||||
["Amount", "5.0000 ETH"],
|
|
||||||
...zeroAddressLines("1", OTHER_ADDR),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://git.eeqj.de/sneak/AutistMask/issues/359 — the output half, in
|
// https://git.eeqj.de/sneak/AutistMask/issues/359 — the output half, in
|
||||||
|
|||||||
Reference in New Issue
Block a user