@reptilianhq/uniswap-sdk 0.2.2
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/NOTICE +4 -0
- package/README.md +176 -0
- package/RELEASING.md +114 -0
- package/dist/abis.d.ts +161 -0
- package/dist/abis.d.ts.map +1 -0
- package/dist/abis.js +21 -0
- package/dist/abis.js.map +1 -0
- package/dist/batch.d.ts +60 -0
- package/dist/batch.d.ts.map +1 -0
- package/dist/batch.js +157 -0
- package/dist/batch.js.map +1 -0
- package/dist/compatibility.d.ts +15 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +57 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/deployments.d.ts +27 -0
- package/dist/deployments.d.ts.map +1 -0
- package/dist/deployments.js +70 -0
- package/dist/deployments.js.map +1 -0
- package/dist/depth.d.ts +24 -0
- package/dist/depth.d.ts.map +1 -0
- package/dist/depth.js +65 -0
- package/dist/depth.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -0
- package/dist/events.d.ts +23 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +27 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/official-sdk.cjs +9 -0
- package/dist/official-sdk.cjs.map +1 -0
- package/dist/official-sdk.d.cts +2 -0
- package/dist/official-sdk.d.cts.map +1 -0
- package/dist/pool.d.ts +30 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +55 -0
- package/dist/pool.js.map +1 -0
- package/dist/providers.d.ts +59 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +110 -0
- package/dist/providers.js.map +1 -0
- package/dist/reads.d.ts +61 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +92 -0
- package/dist/reads.js.map +1 -0
- package/dist/receipts.d.ts +2 -0
- package/dist/receipts.d.ts.map +1 -0
- package/dist/receipts.js +2 -0
- package/dist/receipts.js.map +1 -0
- package/dist/transactions.d.ts +2 -0
- package/dist/transactions.d.ts.map +1 -0
- package/dist/transactions.js +2 -0
- package/dist/transactions.js.map +1 -0
- package/dist/v3-abis.d.ts +525 -0
- package/dist/v3-abis.d.ts.map +1 -0
- package/dist/v3-abis.js +43 -0
- package/dist/v3-abis.js.map +1 -0
- package/dist/v3-receipts.d.ts +28 -0
- package/dist/v3-receipts.d.ts.map +1 -0
- package/dist/v3-receipts.js +68 -0
- package/dist/v3-receipts.js.map +1 -0
- package/dist/v3-transactions.d.ts +107 -0
- package/dist/v3-transactions.d.ts.map +1 -0
- package/dist/v3-transactions.js +323 -0
- package/dist/v3-transactions.js.map +1 -0
- package/dist/v3.d.ts +6 -0
- package/dist/v3.d.ts.map +1 -0
- package/dist/v3.js +6 -0
- package/dist/v3.js.map +1 -0
- package/dist/v4.d.ts +8 -0
- package/dist/v4.d.ts.map +1 -0
- package/dist/v4.js +5 -0
- package/dist/v4.js.map +1 -0
- package/docs/FORK_TESTING.md +24 -0
- package/examples/read-only-consumer.mjs +59 -0
- package/fixtures/receipts/robinhood-mainnet-v3-lifecycle.json +84 -0
- package/fixtures/receipts/robinhood-mainnet-v3-mint.json +42 -0
- package/package.json +124 -0
- package/provenance/mainnet.json +33 -0
- package/provenance/testnet.json +33 -0
- package/scripts/check-conformance.mjs +191 -0
- package/scripts/verify-v3-deployments.mjs +23 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import {
|
|
3
|
+
readV4Pool,
|
|
4
|
+
readV4TickWindow,
|
|
5
|
+
} from '@reptilianhq/uniswap-sdk/v4';
|
|
6
|
+
import { isUniswapSdkError } from '@reptilianhq/uniswap-sdk/errors';
|
|
7
|
+
|
|
8
|
+
const address = number => `0x${number.toString(16).padStart(40, '0')}`;
|
|
9
|
+
const deployment = {
|
|
10
|
+
chainId: 4663,
|
|
11
|
+
poolManager: address(1),
|
|
12
|
+
stateView: address(2),
|
|
13
|
+
quoter: address(3),
|
|
14
|
+
};
|
|
15
|
+
const poolKey = {
|
|
16
|
+
currency0: address(0),
|
|
17
|
+
currency1: address(4),
|
|
18
|
+
fee: 3_000,
|
|
19
|
+
tickSpacing: 32_767,
|
|
20
|
+
hooks: address(0),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Replace this deterministic client with a configured viem PublicClient.
|
|
24
|
+
const publicClient = {
|
|
25
|
+
async getChainId() { return deployment.chainId; },
|
|
26
|
+
async getBlockNumber() { return 100n; },
|
|
27
|
+
async readContract({ functionName, args }) {
|
|
28
|
+
if (functionName === 'poolManager') return deployment.poolManager;
|
|
29
|
+
if (functionName === 'getSlot0') return [1n << 96n, 0, 0, 3_000];
|
|
30
|
+
if (functionName === 'getLiquidity') return 500n;
|
|
31
|
+
if (functionName === 'getTickBitmap') {
|
|
32
|
+
if (args[1] === -1) throw new Error('fixture: bitmap unavailable');
|
|
33
|
+
return 0n;
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`fixture: unexpected ${functionName}`);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const pool = await readV4Pool(publicClient, deployment, poolKey);
|
|
40
|
+
assert.equal(pool.blockNumber, 100n);
|
|
41
|
+
assert.equal(pool.liquidity, 500n);
|
|
42
|
+
|
|
43
|
+
const ticks = await readV4TickWindow(publicClient, deployment, poolKey, {
|
|
44
|
+
fromWord: -1,
|
|
45
|
+
toWord: 0,
|
|
46
|
+
blockNumber: pool.blockNumber,
|
|
47
|
+
});
|
|
48
|
+
assert.equal(ticks.partial, true);
|
|
49
|
+
assert.deepEqual(ticks.failedWords, [-1]);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
await readV4Pool(publicClient, { ...deployment, chainId: 1 }, poolKey);
|
|
53
|
+
assert.fail('the wrong chain must be rejected');
|
|
54
|
+
} catch (error) {
|
|
55
|
+
assert.equal(isUniswapSdkError(error), true);
|
|
56
|
+
assert.equal(error.code, 'CHAIN_MISMATCH');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log('Read-only consumer example passed.');
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"deploymentId": "robinhood-mainnet-v3",
|
|
4
|
+
"chainId": 4663,
|
|
5
|
+
"abiRevision": "uniswap-v3-core-periphery-1.0.0",
|
|
6
|
+
"recordedHead": 60266150,
|
|
7
|
+
"minimumFinalityDepth": 5000,
|
|
8
|
+
"transactionHash": "0x011845afe62d555d6667a6f8e3b5cf4d60152bac613d04853d879f58b60e1e15",
|
|
9
|
+
"blockHash": "0x53bab62a1495b95392570d5fb20aa1c1d5fa9f868839f71ed080b82b1d68b6df",
|
|
10
|
+
"blockNumber": 60175962,
|
|
11
|
+
"status": "success",
|
|
12
|
+
"manager": "0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3",
|
|
13
|
+
"recipient": "0x62c327a39c84ca646044B28Aa169cAeCDE318960",
|
|
14
|
+
"closedTokenId": "1127306",
|
|
15
|
+
"mintedTokenId": "1130874",
|
|
16
|
+
"logSelection": "position-manager lifecycle evidence",
|
|
17
|
+
"logs": [
|
|
18
|
+
{
|
|
19
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
20
|
+
"topics": [
|
|
21
|
+
"0x40d0efd1a53d60ecbf40971b9daf7dc90178c3aadc7aab1765632738fa8b8f01",
|
|
22
|
+
"0x000000000000000000000000000000000000000000000000000000000011338a"
|
|
23
|
+
],
|
|
24
|
+
"data": "0x00000000000000000000000062c327a39c84ca646044b28aa169caecde31896000000000000000000000000000000000000000000000000000001b965f671e4c0000000000000000000000000000000000000000000000001cf0c05cf94e63e4"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
28
|
+
"topics": [
|
|
29
|
+
"0x26f6a048ee9138f2c0ce266f322cb99228e8d619ae2bff30c67f8dcf9d2377b4",
|
|
30
|
+
"0x000000000000000000000000000000000000000000000000000000000011338a"
|
|
31
|
+
],
|
|
32
|
+
"data": "0x00000000000000000000000000000000000000000000000082e986b70fbead3100000000000000000000000000000000000000000000000000007b508432fee100000000000000000000000000000000000000000000000d719e0d747b720be3"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
36
|
+
"topics": [
|
|
37
|
+
"0x40d0efd1a53d60ecbf40971b9daf7dc90178c3aadc7aab1765632738fa8b8f01",
|
|
38
|
+
"0x000000000000000000000000000000000000000000000000000000000011338a"
|
|
39
|
+
],
|
|
40
|
+
"data": "0x00000000000000000000000062c327a39c84ca646044b28aa169caecde31896000000000000000000000000000000000000000000000000000007b508432fee100000000000000000000000000000000000000000000000d719e0d747b720be3"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
44
|
+
"topics": [
|
|
45
|
+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
46
|
+
"0x00000000000000000000000062c327a39c84ca646044b28aa169caecde318960",
|
|
47
|
+
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
48
|
+
"0x000000000000000000000000000000000000000000000000000000000011338a"
|
|
49
|
+
],
|
|
50
|
+
"data": "0x"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
54
|
+
"topics": [
|
|
55
|
+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
56
|
+
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
57
|
+
"0x00000000000000000000000062c327a39c84ca646044b28aa169caecde318960",
|
|
58
|
+
"0x000000000000000000000000000000000000000000000000000000000011417a"
|
|
59
|
+
],
|
|
60
|
+
"data": "0x"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
64
|
+
"topics": [
|
|
65
|
+
"0x3067048beee31b25b2f1681f88dac838c8bba36af25bfb2b7cf7473a5847e35f",
|
|
66
|
+
"0x000000000000000000000000000000000000000000000000000000000011417a"
|
|
67
|
+
],
|
|
68
|
+
"data": "0x00000000000000000000000000000000000000000000000083813d777a4bdacb000000000000000000000000000000000000000000000000000754af9a0c47ff000000000000000000000000000000000000000000000007e76839352a9495ae"
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"expected": {
|
|
72
|
+
"closed": {
|
|
73
|
+
"liquidityRemoved": "9433219015305506097",
|
|
74
|
+
"amount0Collected": "165918405172525",
|
|
75
|
+
"amount1Collected": "250080047057793478599",
|
|
76
|
+
"burned": true
|
|
77
|
+
},
|
|
78
|
+
"minted": {
|
|
79
|
+
"liquidityAdded": "9475922674326428363",
|
|
80
|
+
"amount0Added": "2063438017480703",
|
|
81
|
+
"amount1Added": "145801849036816553390"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"deploymentId": "robinhood-mainnet-v3",
|
|
4
|
+
"chainId": 4663,
|
|
5
|
+
"abiRevision": "uniswap-v3-core-periphery-1.0.0",
|
|
6
|
+
"recordedHead": 60266150,
|
|
7
|
+
"minimumFinalityDepth": 5000,
|
|
8
|
+
"transactionHash": "0x010857a8063c93493bfd3fb010ef8af77b0ac64a0866f86ee542396c2eefe105",
|
|
9
|
+
"blockHash": "0xa9bcdc3119d06bee5949915e974d0f33163fa30782ce0a3f6b238c683f50f239",
|
|
10
|
+
"blockNumber": 60183858,
|
|
11
|
+
"status": "success",
|
|
12
|
+
"manager": "0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3",
|
|
13
|
+
"recipient": "0xB4AcBc082b5E7DEd571c98eE4257778A9d784B36",
|
|
14
|
+
"tokenId": "1131007",
|
|
15
|
+
"logSelection": "position-manager mint and liquidity evidence",
|
|
16
|
+
"logs": [
|
|
17
|
+
{
|
|
18
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
19
|
+
"topics": [
|
|
20
|
+
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
|
|
21
|
+
"0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
22
|
+
"0x000000000000000000000000b4acbc082b5e7ded571c98ee4257778a9d784b36",
|
|
23
|
+
"0x00000000000000000000000000000000000000000000000000000000001141ff"
|
|
24
|
+
],
|
|
25
|
+
"data": "0x"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"address": "0x73991a25c818bf1f1128deaab1492d45638de0d3",
|
|
29
|
+
"topics": [
|
|
30
|
+
"0x3067048beee31b25b2f1681f88dac838c8bba36af25bfb2b7cf7473a5847e35f",
|
|
31
|
+
"0x00000000000000000000000000000000000000000000000000000000001141ff"
|
|
32
|
+
],
|
|
33
|
+
"data": "0x0000000000000000000000000000000000000000000000007e059550b2ea9d4c00000000000000000000000000000000000000000000000552d668a9c55f844b000000000000000000000000000000000000000000000000001bc9d7505123ac"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"expected": {
|
|
37
|
+
"mintedTokenId": "1131007",
|
|
38
|
+
"liquidityAdded": "9080828397494115660",
|
|
39
|
+
"amount0Added": "98202793803044062283",
|
|
40
|
+
"amount1Added": "7821750973834156"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reptilianhq/uniswap-sdk",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Deployment-explicit Uniswap observations and reviewed transaction material.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"docs",
|
|
11
|
+
"examples",
|
|
12
|
+
"fixtures",
|
|
13
|
+
"provenance",
|
|
14
|
+
"scripts/check-conformance.mjs",
|
|
15
|
+
"scripts/verify-v3-deployments.mjs",
|
|
16
|
+
"README.md",
|
|
17
|
+
"RELEASING.md",
|
|
18
|
+
"NOTICE",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=24"
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./v4": {
|
|
32
|
+
"types": "./dist/v4.d.ts",
|
|
33
|
+
"import": "./dist/v4.js"
|
|
34
|
+
},
|
|
35
|
+
"./v3": {
|
|
36
|
+
"types": "./dist/v3.d.ts",
|
|
37
|
+
"import": "./dist/v3.js"
|
|
38
|
+
},
|
|
39
|
+
"./deployments": {
|
|
40
|
+
"types": "./dist/deployments.d.ts",
|
|
41
|
+
"import": "./dist/deployments.js"
|
|
42
|
+
},
|
|
43
|
+
"./compatibility": {
|
|
44
|
+
"types": "./dist/compatibility.d.ts",
|
|
45
|
+
"import": "./dist/compatibility.js"
|
|
46
|
+
},
|
|
47
|
+
"./transactions": {
|
|
48
|
+
"types": "./dist/transactions.d.ts",
|
|
49
|
+
"import": "./dist/transactions.js"
|
|
50
|
+
},
|
|
51
|
+
"./receipts": {
|
|
52
|
+
"types": "./dist/receipts.d.ts",
|
|
53
|
+
"import": "./dist/receipts.js"
|
|
54
|
+
},
|
|
55
|
+
"./batch": {
|
|
56
|
+
"types": "./dist/batch.d.ts",
|
|
57
|
+
"import": "./dist/batch.js"
|
|
58
|
+
},
|
|
59
|
+
"./abis": {
|
|
60
|
+
"types": "./dist/abis.d.ts",
|
|
61
|
+
"import": "./dist/abis.js"
|
|
62
|
+
},
|
|
63
|
+
"./errors": {
|
|
64
|
+
"types": "./dist/errors.d.ts",
|
|
65
|
+
"import": "./dist/errors.js"
|
|
66
|
+
},
|
|
67
|
+
"./providers": {
|
|
68
|
+
"types": "./dist/providers.d.ts",
|
|
69
|
+
"import": "./dist/providers.js"
|
|
70
|
+
},
|
|
71
|
+
"./provenance/mainnet.json": "./provenance/mainnet.json",
|
|
72
|
+
"./provenance/testnet.json": "./provenance/testnet.json"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "tsc -p tsconfig.build.json",
|
|
76
|
+
"check": "npm run build && npm run typecheck && npm run lint && npm run test:run && npm run test:runtime && npm run test:consumer && npm run check:conformance && npm run check:publisher && npm run test:release && npm run check:package",
|
|
77
|
+
"typecheck": "tsc --noEmit",
|
|
78
|
+
"lint": "eslint . --max-warnings 0",
|
|
79
|
+
"test:run": "vitest run src",
|
|
80
|
+
"test:runtime": "node scripts/runtime-smoke.mjs",
|
|
81
|
+
"test:fork": "vitest run src/v3-mainnet.fork.test.ts",
|
|
82
|
+
"test:live-compatibility": "npm run build && node scripts/verify-v3-deployments.mjs",
|
|
83
|
+
"test:consumer": "node examples/read-only-consumer.mjs",
|
|
84
|
+
"check:conformance": "node scripts/check-conformance.mjs . && node --test scripts/check-conformance.node-test.mjs",
|
|
85
|
+
"check:publisher": "node scripts/artifacts/check.mjs",
|
|
86
|
+
"test:release": "node --test scripts/artifacts/publisher.test.mjs scripts/release.test.mjs",
|
|
87
|
+
"check:package": "publint && attw --pack . --profile esm-only",
|
|
88
|
+
"prepack": "npm run build"
|
|
89
|
+
},
|
|
90
|
+
"dependencies": {
|
|
91
|
+
"@uniswap/sdk-core": "7.19.2",
|
|
92
|
+
"@uniswap/v4-sdk": "2.3.3"
|
|
93
|
+
},
|
|
94
|
+
"peerDependencies": {
|
|
95
|
+
"viem": ">=2.55.0 <3"
|
|
96
|
+
},
|
|
97
|
+
"devDependencies": {
|
|
98
|
+
"@arethetypeswrong/cli": "0.18.5",
|
|
99
|
+
"@eslint/js": "10.0.1",
|
|
100
|
+
"@hegeldev/hegel": "0.4.3",
|
|
101
|
+
"@types/node": "24.13.2",
|
|
102
|
+
"eslint": "10.6.0",
|
|
103
|
+
"globals": "17.7.0",
|
|
104
|
+
"publint": "0.3.23",
|
|
105
|
+
"typescript": "6.0.3",
|
|
106
|
+
"typescript-eslint": "8.62.0",
|
|
107
|
+
"viem": "2.55.2",
|
|
108
|
+
"vitest": "4.1.9"
|
|
109
|
+
},
|
|
110
|
+
"repository": {
|
|
111
|
+
"type": "git",
|
|
112
|
+
"url": "git+https://github.com/ReptilianHQ/uniswap-sdk.git"
|
|
113
|
+
},
|
|
114
|
+
"publishConfig": {
|
|
115
|
+
"registry": "https://registry.npmjs.org",
|
|
116
|
+
"access": "public"
|
|
117
|
+
},
|
|
118
|
+
"packageManager": "npm@11.5.2",
|
|
119
|
+
"reptilianRelease": {
|
|
120
|
+
"schemaVersion": 1,
|
|
121
|
+
"group": "uniswap-sdk",
|
|
122
|
+
"sourceSha": "d02bfdd8f80b6f95c7fc573ccd4eb17e6de6a0cf"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"deploymentId": "robinhood-mainnet-v3",
|
|
4
|
+
"chainId": 4663,
|
|
5
|
+
"reviewedAt": "2026-09-11",
|
|
6
|
+
"abiRevision": "uniswap-v3-core-periphery-1.0.0",
|
|
7
|
+
"provenance": "official",
|
|
8
|
+
"explorerVerification": "official",
|
|
9
|
+
"contracts": {
|
|
10
|
+
"factory": "0x1f7d7550B1b028f7571E69A784071F0205FD2EfA",
|
|
11
|
+
"nonfungiblePositionManager": "0x73991a25C818Bf1f1128dEAaB1492D45638DE0D3",
|
|
12
|
+
"quoterV2": "0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7",
|
|
13
|
+
"swapRouter02": "0xcaf681a66d020601342297493863e78c959e5cb2",
|
|
14
|
+
"wrappedNative": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
|
|
15
|
+
"multicall3": "0xca11bde05977b3631167028862be2a173976ca11"
|
|
16
|
+
},
|
|
17
|
+
"runtimeCodeHashes": {
|
|
18
|
+
"factory": "0xec72b1abd1f2faee020cfea9c646bd8994f9fb389054f6e574f103a895091739",
|
|
19
|
+
"nonfungiblePositionManager": "0x0a493d1af3d0f25fed8efa205244ebee14114267a08647fc38c515c7cd6ead4f",
|
|
20
|
+
"quoterV2": "0x3db0868d945e9304c9bc6a8b2181948109ea617647142f3c4083e14393496a28",
|
|
21
|
+
"swapRouter02": "0x6f36c378e272c6324c48f045182bcb54bd8ad654cf9ebd42e8893d52c4cb25dc",
|
|
22
|
+
"wrappedNative": "0x5706be52f64875fee65a2cec0d80e47a23d8793cbe85d214b48445e2d05f5353",
|
|
23
|
+
"multicall3": "0xd5c15df687b16f2ff992fc8d767b4216323184a2bbc6ee2f9c398c318e770891"
|
|
24
|
+
},
|
|
25
|
+
"runtimeCodeHashPin": {
|
|
26
|
+
"blockNumber": 60266150,
|
|
27
|
+
"rpc": "https://rpc.mainnet.chain.robinhood.com"
|
|
28
|
+
},
|
|
29
|
+
"limitations": [
|
|
30
|
+
"Compatibility checks chain identity, exact runtime code hashes, and position-manager factory/WETH9 wiring.",
|
|
31
|
+
"Runtime code hashes establish deployed-code identity; they do not establish source verification or custom-hook compatibility."
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"deploymentId": "robinhood-testnet-v3",
|
|
4
|
+
"chainId": 46630,
|
|
5
|
+
"reviewedAt": "2026-09-11",
|
|
6
|
+
"abiRevision": "uniswap-v3-core-periphery-1.0.0",
|
|
7
|
+
"provenance": "reviewed-testnet",
|
|
8
|
+
"explorerVerification": "partial",
|
|
9
|
+
"contracts": {
|
|
10
|
+
"factory": "0xdf9e3D6ffaC4513dD7b053212bbECcbCD15ec932",
|
|
11
|
+
"nonfungiblePositionManager": "0xFFe6CFc4f759b65f9B62c9D05A9E21a78cE93e12",
|
|
12
|
+
"quoterV2": "0xDDcBe4989C8171F721c5e683C9C6339B59718213",
|
|
13
|
+
"swapRouter02": "0xb79cB26e90EBBD9bC02c75267c9a86dBa1AFedB7",
|
|
14
|
+
"wrappedNative": "0x7943e237c7F95DA44E0301572D358911207852Fa",
|
|
15
|
+
"multicall3": "0xca11bde05977b3631167028862be2a173976ca11"
|
|
16
|
+
},
|
|
17
|
+
"runtimeCodeHashes": {
|
|
18
|
+
"factory": "0x75c5bbc7989daa85188d9e4c9f989271d8bcb2abad3d47e6e47d3c0c5bff02c2",
|
|
19
|
+
"nonfungiblePositionManager": "0xe40cd590528ac8b67b428579035fe391e502c38271623777692c50834688e9d5",
|
|
20
|
+
"quoterV2": "0x724c4956e1c61fd13285a92685337df60254bc67f775e7268da2fc5cc79d5343",
|
|
21
|
+
"swapRouter02": "0xdce781dc17d5f98e3ea0b72d88639a5995ccbba6e11bc01f2057a9409dc8c724",
|
|
22
|
+
"wrappedNative": "0x5706be52f64875fee65a2cec0d80e47a23d8793cbe85d214b48445e2d05f5353",
|
|
23
|
+
"multicall3": "0xd5c15df687b16f2ff992fc8d767b4216323184a2bbc6ee2f9c398c318e770891"
|
|
24
|
+
},
|
|
25
|
+
"runtimeCodeHashPin": {
|
|
26
|
+
"blockNumber": 117449391,
|
|
27
|
+
"rpc": "https://rpc.testnet.chain.robinhood.com"
|
|
28
|
+
},
|
|
29
|
+
"limitations": [
|
|
30
|
+
"The factory and position manager were reviewed against pinned Uniswap v3 source artifacts; the remaining addresses have partial explorer verification.",
|
|
31
|
+
"Runtime code hashes establish deployed-code identity; they do not establish source verification or custom-hook compatibility."
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Vendored copy of ReptilianHQ/reptilian scripts/check-sdk-conformance.mjs, the shared Protocol SDK
|
|
4
|
+
// Standard's conformance script (docs/SDK_STANDARDS.md there). This standalone package
|
|
5
|
+
// cannot read the private source, so the source repository checks this copy against its
|
|
6
|
+
// own on every change. Do not edit the body below; the adjacent self-test fails if it no
|
|
7
|
+
// longer matches the recorded hash. Invoked as `node scripts/check-conformance.mjs .`.
|
|
8
|
+
// Canonical body sha256: e03bec3ea1db3451f3306ca5dd48f432dd061db02a3c9dd445c1f557e6408bb4
|
|
9
|
+
|
|
10
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join, relative, resolve, sep } from 'node:path';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
|
|
14
|
+
export const requiredCapabilityExports = [
|
|
15
|
+
'./deployments',
|
|
16
|
+
'./compatibility',
|
|
17
|
+
'./errors',
|
|
18
|
+
'./transactions',
|
|
19
|
+
'./receipts',
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
// Property-based invariant suites required per exported capability. See
|
|
23
|
+
// docs/SDK_STANDARDS.md, "Invariant testing for capital-moving flows".
|
|
24
|
+
export const requiredInvariantSuites = [
|
|
25
|
+
['./transactions', 'transactions.hegel.test.ts'],
|
|
26
|
+
['./receipts', 'receipts.hegel.test.ts'],
|
|
27
|
+
['./math', 'math.hegel.test.ts'],
|
|
28
|
+
['./economics', 'economics.hegel.test.ts'],
|
|
29
|
+
['./swap', 'swap.hegel.test.ts'],
|
|
30
|
+
['./fees', 'fees.hegel.test.ts'],
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// Invariant suites a package has not adopted yet, keyed by repository-relative
|
|
34
|
+
// root. Only the listed suites downgrade to warnings; any other missing suite
|
|
35
|
+
// fails. Remove a suite once the package adopts it.
|
|
36
|
+
export const invariantAdoptionPending = new Map([
|
|
37
|
+
// Every governed package in this repository has adopted its suites. Add a
|
|
38
|
+
// [root, Set(suites)] entry only for a new package that has not yet.
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
// Returns [{ suite, issue }] so callers can decide per suite whether a gap is
|
|
42
|
+
// pending adoption or a failure.
|
|
43
|
+
export function invariantSuiteFindings(manifest, sourceFiles = new Map()) {
|
|
44
|
+
if (sourceFiles.size === 0) return [];
|
|
45
|
+
const findings = [];
|
|
46
|
+
for (const [exportPath, suite] of requiredInvariantSuites) {
|
|
47
|
+
if (!manifest.exports?.[exportPath]) continue;
|
|
48
|
+
const source = sourceFiles.get(suite);
|
|
49
|
+
if (!source) {
|
|
50
|
+
findings.push({ suite, missing: true, issue: `${exportPath} is exported but src/${suite} is missing (property-based invariant suite)` });
|
|
51
|
+
} else if (!source.includes('@hegeldev/hegel')) {
|
|
52
|
+
findings.push({ suite, missing: false, issue: `src/${suite} must use @hegeldev/hegel for its invariant properties` });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return findings;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function invariantSuiteIssues(manifest, sourceFiles = new Map()) {
|
|
59
|
+
return invariantSuiteFindings(manifest, sourceFiles).map(({ issue }) => issue);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function sdkConformanceIssues(manifest, sourceFiles = new Map(), options = {}) {
|
|
63
|
+
const issues = [];
|
|
64
|
+
if (manifest.type !== 'module') issues.push('package must use ESM (`type: module`)');
|
|
65
|
+
if (manifest.sideEffects !== false) issues.push('package must declare `sideEffects: false`');
|
|
66
|
+
if (!Array.isArray(manifest.files) || !manifest.files.includes('dist') || !manifest.files.includes('README.md')) {
|
|
67
|
+
issues.push('published files must include `dist` and `README.md`');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
for (const exportPath of requiredCapabilityExports) {
|
|
71
|
+
const entry = manifest.exports?.[exportPath];
|
|
72
|
+
if (!entry) {
|
|
73
|
+
issues.push(`missing required capability export ${exportPath}`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (typeof entry.types !== 'string' || !entry.types.startsWith('./dist/') || !entry.types.endsWith('.d.ts')) {
|
|
77
|
+
issues.push(`${exportPath} types must resolve to a declaration under ./dist`);
|
|
78
|
+
}
|
|
79
|
+
if (typeof entry.import !== 'string' || !entry.import.startsWith('./dist/') || !entry.import.endsWith('.js')) {
|
|
80
|
+
issues.push(`${exportPath} import must resolve to ESM JavaScript under ./dist`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!manifest.exports?.['./abis'] && !manifest.exports?.['./idl']) {
|
|
85
|
+
issues.push('missing chain artifact export (`./abis` for EVM or `./idl` for Solana)');
|
|
86
|
+
}
|
|
87
|
+
if (!manifest.exports?.['./provenance/mainnet.json'] && !manifest.exports?.['./provenance/testnet.json']) {
|
|
88
|
+
issues.push('missing an exported deployment provenance document');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (sourceFiles.size > 0) {
|
|
92
|
+
const errorsSource = sourceFiles.get('errors.ts');
|
|
93
|
+
if (!errorsSource) {
|
|
94
|
+
issues.push('missing src/errors.ts for the exported SDK error contract');
|
|
95
|
+
} else {
|
|
96
|
+
const errorContractChecks = [
|
|
97
|
+
[/export\s+type\s+\w*ErrorCode/u, 'a public error-code union'],
|
|
98
|
+
[/export\s+class\s+\w+\s+extends\s+Error/u, 'an exported Error subclass'],
|
|
99
|
+
[/readonly\s+code/u, 'a readonly error code'],
|
|
100
|
+
[/\btoJSON\s*\(/u, 'a JSON representation'],
|
|
101
|
+
[/export\s+function\s+is\w*Error\s*\(/u, 'an exported error type guard'],
|
|
102
|
+
];
|
|
103
|
+
for (const [pattern, label] of errorContractChecks) {
|
|
104
|
+
if (!pattern.test(errorsSource)) issues.push(`src/errors.ts must expose ${label}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const [path, source] of sourceFiles) {
|
|
110
|
+
if (path.endsWith('.test.ts') || path.endsWith('.spec.ts')) continue;
|
|
111
|
+
if (/throw\s+new\s+Error\s*\(/u.test(source)) {
|
|
112
|
+
issues.push(`${path} throws an untyped Error instead of the SDK error contract`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (options.requireInvariantSuites !== false) {
|
|
116
|
+
issues.push(...invariantSuiteIssues(manifest, sourceFiles));
|
|
117
|
+
}
|
|
118
|
+
return issues;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function collectTypeScriptSources(directory, base = directory, result = new Map()) {
|
|
122
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
123
|
+
const path = join(directory, entry.name);
|
|
124
|
+
if (entry.isDirectory()) collectTypeScriptSources(path, base, result);
|
|
125
|
+
else if (entry.isFile() && entry.name.endsWith('.ts')) {
|
|
126
|
+
result.set(relative(base, path), readFileSync(path, 'utf8'));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function loadSdkPackage(packageRoot) {
|
|
133
|
+
const manifestPath = join(packageRoot, 'package.json');
|
|
134
|
+
const sourceRoot = join(packageRoot, 'src');
|
|
135
|
+
if (!existsSync(manifestPath)) return { error: `missing package manifest at ${manifestPath}` };
|
|
136
|
+
if (!existsSync(sourceRoot)) return { error: `missing SDK source directory at ${sourceRoot}` };
|
|
137
|
+
return {
|
|
138
|
+
manifest: JSON.parse(readFileSync(manifestPath, 'utf8')),
|
|
139
|
+
sourceFiles: collectTypeScriptSources(sourceRoot),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function checkSdkPackage(packageRoot, options = {}) {
|
|
144
|
+
const loaded = loadSdkPackage(packageRoot);
|
|
145
|
+
if (loaded.error) return [loaded.error];
|
|
146
|
+
return sdkConformanceIssues(loaded.manifest, loaded.sourceFiles, options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const repositoryRoot = resolve(fileURLToPath(new URL('..', import.meta.url)));
|
|
150
|
+
|
|
151
|
+
// Repository-relative, forward-slash form used as the pending-adoption key,
|
|
152
|
+
// anchored on this script's location so the key is the same from any cwd.
|
|
153
|
+
export function pendingAdoptionKey(packageRoot) {
|
|
154
|
+
return relative(repositoryRoot, resolve(packageRoot)).split(sep).join('/');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Splits a package's issues into failures and pending-adoption warnings in one pass.
|
|
158
|
+
export function classifySdkPackage(packageRoot) {
|
|
159
|
+
const loaded = loadSdkPackage(packageRoot);
|
|
160
|
+
if (loaded.error) return { failures: [loaded.error], warnings: [] };
|
|
161
|
+
const base = sdkConformanceIssues(loaded.manifest, loaded.sourceFiles, { requireInvariantSuites: false });
|
|
162
|
+
const pendingSuites = invariantAdoptionPending.get(pendingAdoptionKey(packageRoot)) ?? new Set();
|
|
163
|
+
const failures = [...base];
|
|
164
|
+
const warnings = [];
|
|
165
|
+
for (const { suite, issue, missing } of invariantSuiteFindings(loaded.manifest, loaded.sourceFiles)) {
|
|
166
|
+
// Pending adoption means "not written yet": only a missing file is
|
|
167
|
+
// downgraded. A file that exists without Hegel is a failure everywhere.
|
|
168
|
+
(missing && pendingSuites.has(suite) ? warnings : failures).push(issue);
|
|
169
|
+
}
|
|
170
|
+
return { failures, warnings };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const invokedPath = process.argv[1] ? resolve(process.argv[1]) : null;
|
|
174
|
+
if (invokedPath === fileURLToPath(import.meta.url)) {
|
|
175
|
+
const packageRoots = process.argv.slice(2);
|
|
176
|
+
if (packageRoots.length === 0) {
|
|
177
|
+
console.error('Usage: node scripts/check-sdk-conformance.mjs <package-root> [...]');
|
|
178
|
+
process.exitCode = 2;
|
|
179
|
+
} else {
|
|
180
|
+
const results = packageRoots.map((packageRoot) => [packageRoot, classifySdkPackage(packageRoot)]);
|
|
181
|
+
const failures = results.flatMap(([root, { failures: f }]) => f.map((issue) => `${root}: ${issue}`));
|
|
182
|
+
const warnings = results.flatMap(([root, { warnings: w }]) => w.map((issue) => `${root}: pending adoption: ${issue}`));
|
|
183
|
+
if (warnings.length > 0) console.warn(warnings.join('\n'));
|
|
184
|
+
if (failures.length > 0) {
|
|
185
|
+
console.error(failures.join('\n'));
|
|
186
|
+
process.exitCode = 1;
|
|
187
|
+
} else {
|
|
188
|
+
console.log(`SDK conformance passed for ${packageRoots.join(', ')}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createPublicClient, http } from 'viem';
|
|
2
|
+
import {
|
|
3
|
+
robinhoodUniswapV3Mainnet,
|
|
4
|
+
robinhoodUniswapV3Testnet,
|
|
5
|
+
verifyUniswapV3Compatibility,
|
|
6
|
+
} from '../dist/v3.js';
|
|
7
|
+
|
|
8
|
+
const targets = [
|
|
9
|
+
{
|
|
10
|
+
deployment: robinhoodUniswapV3Mainnet,
|
|
11
|
+
rpcUrl: process.env.UNISWAP_MAINNET_RPC_URL?.trim() || 'https://rpc.mainnet.chain.robinhood.com',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
deployment: robinhoodUniswapV3Testnet,
|
|
15
|
+
rpcUrl: process.env.UNISWAP_TESTNET_RPC_URL?.trim() || 'https://rpc.testnet.chain.robinhood.com',
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
for (const { deployment, rpcUrl } of targets) {
|
|
20
|
+
const client = createPublicClient({ transport: http(rpcUrl) });
|
|
21
|
+
const report = await verifyUniswapV3Compatibility(client, deployment);
|
|
22
|
+
process.stdout.write(`ok - ${deployment.id}: ${Object.keys(report.runtimeCodeHashes).length} runtime hashes and manager wiring verified\n`);
|
|
23
|
+
}
|