@blossm/contract-addresses-trusted-forwarder 0.0.0-stage → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +83 -2
- package/deps.js +5 -0
- package/index.js +31 -0
- package/package.json +22 -4
- package/test/index.js +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Blossm
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,84 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @blossm/contract-addresses-trusted-forwarder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Static Juicebox V6 `ERC2771Forwarder` deployment lookup. Source records are
|
|
4
|
+
pinned to `Bananapus/deploy-all-v6` commit
|
|
5
|
+
`c62b3ac81bfc5603b6771e8ad801eb2236022947`. Lookup performs no network requests.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import contracts from "@blossm/contract-addresses-trusted-forwarder";
|
|
9
|
+
|
|
10
|
+
const address = contracts.erc2771ForwarderContract(1);
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## erc2771ForwarderContract(chainId)
|
|
14
|
+
|
|
15
|
+
Accepts a positive safe-integer JavaScript number from the supported-chain
|
|
16
|
+
table. Returns the lowercase V6 address string. Numeric strings, arrays,
|
|
17
|
+
objects, fractions, zero and other invalid values are rejected without coercion.
|
|
18
|
+
|
|
19
|
+
Invalid input throws the shared `@blossm/errors` internal-server error with
|
|
20
|
+
`chainId must be a positive safe integer`. Unsupported numeric IDs throw the
|
|
21
|
+
same error type with `Unsupported chainId: <id>`. These report unsupported
|
|
22
|
+
configuration; no fallback address is selected. Only own table entries count.
|
|
23
|
+
|
|
24
|
+
## Supported V6 deployment records
|
|
25
|
+
|
|
26
|
+
All eight records point to `0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2`.
|
|
27
|
+
Polygon is not supported by this pinned table.
|
|
28
|
+
|
|
29
|
+
| Chain | ID | Deployment directory | Artifact SHA256 |
|
|
30
|
+
| ---------------- | -------: | -------------------- | ------------------------------------------------------------------ |
|
|
31
|
+
| Ethereum | 1 | `ethereum` | `fe4b86b2945907e5e8e467c894e1dc5653a116a51a4c561bd536c2e5bc47d1c8` |
|
|
32
|
+
| Optimism | 10 | `optimism` | `22b2afda37e1e21fd37ab00e12cc6512d824d083ca193dd30a207378e83e988d` |
|
|
33
|
+
| Base | 8453 | `base` | `2d445573481b9afa3555e6e5fa12dea53fad7a7283f5acb742c97274c0f352fd` |
|
|
34
|
+
| Arbitrum | 42161 | `arbitrum` | `5e466bce4fc88915038ec59c0136d9764aa627755d2fa14a995900ef51cb0f95` |
|
|
35
|
+
| Ethereum Sepolia | 11155111 | `sepolia` | `4acf67e1b2fd496fcdfe0af8ad351e9f10449714617b26055cfa56f9a04b7991` |
|
|
36
|
+
| Base Sepolia | 84532 | `base_sepolia` | `cec05b9232236b937fd5715372517c32f97f11cefdd6c685e52100aff7684b14` |
|
|
37
|
+
| Optimism Sepolia | 11155420 | `optimism_sepolia` | `b26a655cb20d7c111568b84b19d5f3d551d20fe21754f2d11a1667a112482268` |
|
|
38
|
+
| Arbitrum Sepolia | 421614 | `arbitrum_sepolia` | `cf7a8d6da3a7a5c79d5a460ca6c9895ac72081921c3d0b81ff6720aab80351fa` |
|
|
39
|
+
|
|
40
|
+
This lookup explicitly selects the Juicebox V6 deployment family. It does not
|
|
41
|
+
fall back to historical V4/V5 forwarders, discover arbitrary ERC-2771
|
|
42
|
+
contracts, verify an RPC endpoint's chain, or prove that a target trusts the
|
|
43
|
+
forwarder. Callers own those checks and the contract's EIP-712 domain/signing
|
|
44
|
+
configuration. The pinned artifacts record constructor name `Juicebox`;
|
|
45
|
+
callers must verify the actual signing domain instead of assuming an app name.
|
|
46
|
+
|
|
47
|
+
## Provenance
|
|
48
|
+
|
|
49
|
+
- Repository: `Bananapus/deploy-all-v6`.
|
|
50
|
+
- [Pinned deployment-source revision](https://github.com/Bananapus/deploy-all-v6/tree/c62b3ac81bfc5603b6771e8ad801eb2236022947).
|
|
51
|
+
- [Ethereum deployment artifact](https://github.com/Bananapus/deploy-all-v6/blob/c62b3ac81bfc5603b6771e8ad801eb2236022947/deployments/ethereum/ERC2771Forwarder.json).
|
|
52
|
+
- Artifact paths: `deployments/<directory>/ERC2771Forwarder.json`, with directory/hash pairs above.
|
|
53
|
+
- Sorted `[chainId, lowercaseAddress]` projection SHA256: `2529ebbf4c7a7855d1d91e210fa75630ba451aa0185790d54cd17e2778703932`.
|
|
54
|
+
|
|
55
|
+
Verified 2026-10-22 from the local deployment repository: all eight artifact
|
|
56
|
+
bytes match the pinned commit, chain IDs match the table, and each recorded
|
|
57
|
+
receipt has successful status. All eight artifact ABIs match the retained
|
|
58
|
+
`@blossm/contract-abis-trusted-forwarder` interface. The old WIP selected V5;
|
|
59
|
+
the user explicitly selected V6 before this package was committed.
|
|
60
|
+
|
|
61
|
+
No fresh chain RPC, canonical receipt or deployed-bytecode check was performed.
|
|
62
|
+
The successful receipts are committed source evidence, not a live-state claim.
|
|
63
|
+
These artifact hashes and source revision allow the data comparison to be
|
|
64
|
+
repeated from another checkout without access to this machine's paths.
|
|
65
|
+
|
|
66
|
+
The address checksum hashes JSON-serialized pairs sorted numerically by chain
|
|
67
|
+
ID. An update needs reviewed V6 deployment records and a deliberate update of
|
|
68
|
+
the table, provenance and test checksum. Normal tests are offline.
|
|
69
|
+
|
|
70
|
+
## Dependencies and tests
|
|
71
|
+
|
|
72
|
+
Runtime dependency: `@blossm/errors`, provided through `deps.js` in the standard
|
|
73
|
+
Toolbox pattern. Package-local tests use Mocha/Chai and Node's built-in crypto;
|
|
74
|
+
no mocks or additional runtime dependencies are required.
|
|
75
|
+
|
|
76
|
+
From this directory with workspace dependencies installed:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
node ../../../../../node_modules/mocha/bin/mocha.js --recursive
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Tests pin all eight returned V6 addresses to the source-derived checksum and
|
|
83
|
+
cover malformed/coercing inputs, unsupported chains, shared error semantics
|
|
84
|
+
and inherited numeric properties.
|
package/deps.js
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import deps from "./deps.js";
|
|
2
|
+
|
|
3
|
+
// Juicebox V6 deployments, pinned to deploy-all-v6 in README.md.
|
|
4
|
+
const erc2771ForwarderContract = (chainId) => {
|
|
5
|
+
if (!Number.isSafeInteger(chainId) || chainId <= 0) {
|
|
6
|
+
throw deps.internalServer.message(
|
|
7
|
+
"chainId must be a positive safe integer"
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const forwarders = {
|
|
12
|
+
1: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Ethereum Mainnet
|
|
13
|
+
10: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Optimism
|
|
14
|
+
8453: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Base
|
|
15
|
+
42161: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Arbitrum
|
|
16
|
+
11155111: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Ethereum Sepolia
|
|
17
|
+
84532: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Base Sepolia
|
|
18
|
+
11155420: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Optimism Sepolia
|
|
19
|
+
421614: "0x3ba60b60933916a7c87d0860dcee62a0ce34e3e2", // Arbitrum Sepolia
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
if (!Object.hasOwn(forwarders, chainId)) {
|
|
23
|
+
throw deps.internalServer.message(`Unsupported chainId: ${chainId}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return forwarders[chainId];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
erc2771ForwarderContract,
|
|
31
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blossm/contract-addresses-trusted-forwarder",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Pinned Juicebox V6 ERC2771Forwarder deployment addresses",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"author": "blossm.network",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">= 20.19.0"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "mocha --recursive"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@blossm/errors": "*"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"mocha": "^11.7.0",
|
|
22
|
+
"chai": "^5.2.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/test/index.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { expect } from "chai";
|
|
2
|
+
import { createHash } from "crypto";
|
|
3
|
+
|
|
4
|
+
import contracts from "../index.js";
|
|
5
|
+
|
|
6
|
+
const { erc2771ForwarderContract } = contracts;
|
|
7
|
+
|
|
8
|
+
describe("Juicebox V6 forwarder addresses", () => {
|
|
9
|
+
it("should match the pinned V6 deployment's eight chain/address records", () => {
|
|
10
|
+
const chainIds = [1, 10, 8453, 42161, 84532, 421614, 11155111, 11155420];
|
|
11
|
+
const records = chainIds.map((chainId) => [
|
|
12
|
+
chainId,
|
|
13
|
+
erc2771ForwarderContract(chainId),
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
for (const [, address] of records) {
|
|
17
|
+
expect(address).to.match(/^0x[0-9a-f]{40}$/);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Hash of source-derived, numerically sorted [chainId, lowercaseAddress] pairs.
|
|
21
|
+
const hash = createHash("sha256")
|
|
22
|
+
.update(JSON.stringify(records))
|
|
23
|
+
.digest("hex");
|
|
24
|
+
expect(hash).to.equal(
|
|
25
|
+
"2529ebbf4c7a7855d1d91e210fa75630ba451aa0185790d54cd17e2778703932"
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should reject malformed chain IDs without coercing them", () => {
|
|
30
|
+
for (const chainId of [
|
|
31
|
+
undefined,
|
|
32
|
+
null,
|
|
33
|
+
"1",
|
|
34
|
+
"toString",
|
|
35
|
+
"constructor",
|
|
36
|
+
"__proto__",
|
|
37
|
+
[1],
|
|
38
|
+
{},
|
|
39
|
+
{ valueOf: () => 1 },
|
|
40
|
+
{ toString: () => "1" },
|
|
41
|
+
Symbol("chain"),
|
|
42
|
+
true,
|
|
43
|
+
false,
|
|
44
|
+
0,
|
|
45
|
+
-1,
|
|
46
|
+
1.5,
|
|
47
|
+
NaN,
|
|
48
|
+
Infinity,
|
|
49
|
+
Number.MAX_SAFE_INTEGER + 1,
|
|
50
|
+
]) {
|
|
51
|
+
expect(() => erc2771ForwarderContract(chainId))
|
|
52
|
+
.to.throw("chainId must be a positive safe integer")
|
|
53
|
+
.with.property("statusCode", 500);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("should reject unsupported numeric chain IDs with the shared error", () => {
|
|
58
|
+
for (const chainId of [137, 999, Number.MAX_SAFE_INTEGER]) {
|
|
59
|
+
expect(() => erc2771ForwarderContract(chainId))
|
|
60
|
+
.to.throw(`Unsupported chainId: ${chainId}`)
|
|
61
|
+
.with.property("statusCode", 500);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("should reject numeric entries inherited from Object.prototype", () => {
|
|
66
|
+
const previous = Object.getOwnPropertyDescriptor(Object.prototype, "999");
|
|
67
|
+
Object.defineProperty(Object.prototype, "999", {
|
|
68
|
+
value: "0x1111111111111111111111111111111111111111",
|
|
69
|
+
configurable: true,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
expect(() => erc2771ForwarderContract(999))
|
|
74
|
+
.to.throw("Unsupported chainId: 999")
|
|
75
|
+
.with.property("statusCode", 500);
|
|
76
|
+
} finally {
|
|
77
|
+
if (previous) {
|
|
78
|
+
Object.defineProperty(Object.prototype, "999", previous);
|
|
79
|
+
} else {
|
|
80
|
+
delete Object.prototype[999];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|