@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 @@
|
|
|
1
|
+
{"version":3,"file":"v3-receipts.js","sourceRoot":"","sources":["../src/v3-receipts.ts"],"names":[],"mappings":"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","sourcesContent":["import { decodeEventLog, zeroAddress, type Address, type Hex } from 'viem';\nimport { UniswapSdkError } from './errors.js';\nimport { v3PositionManagerEventAbi } from './v3-abis.js';\n\nexport type V3ReceiptLog = {\n address: Address | string;\n data: Hex;\n topics: readonly [] | readonly [Hex, ...(Hex | Hex[] | null)[]];\n};\n\nfunction decodableTopics(topics: V3ReceiptLog['topics']): [] | [Hex, ...Hex[]] {\n if (topics.some((topic) => typeof topic !== 'string')) return [];\n return [...topics] as [] | [Hex, ...Hex[]];\n}\n\nexport interface V3PositionReceiptEvidence {\n liquidityAdded: bigint;\n amount0Added: bigint;\n amount1Added: bigint;\n liquidityRemoved: bigint;\n amount0Collected: bigint;\n amount1Collected: bigint;\n burned: boolean;\n}\n\ntype PositionManagerEvent =\n | { eventName: 'IncreaseLiquidity'; args: { tokenId: bigint; liquidity: bigint; amount0: bigint; amount1: bigint } }\n | { eventName: 'DecreaseLiquidity'; args: { tokenId: bigint; liquidity: bigint; amount0: bigint; amount1: bigint } }\n | { eventName: 'Collect'; args: { tokenId: bigint; recipient: Address; amount0: bigint; amount1: bigint } }\n | { eventName: 'Transfer'; args: { from: Address; to: Address; tokenId: bigint } };\n\nexport function findV3MintedPositionTokenId(input: {\n logs: readonly V3ReceiptLog[]; manager: Address; recipient: Address;\n}): bigint {\n for (const log of input.logs) {\n if (log.address.toLowerCase() !== input.manager.toLowerCase()) continue;\n try {\n const decoded = decodeEventLog({ abi: v3PositionManagerEventAbi, eventName: 'Transfer', data: log.data, topics: decodableTopics(log.topics) });\n if (decoded.eventName === 'Transfer'\n && decoded.args.from === zeroAddress\n && decoded.args.to.toLowerCase() === input.recipient.toLowerCase()) return decoded.args.tokenId;\n } catch {\n // Unrelated manager logs do not satisfy the required mint evidence.\n }\n }\n throw new UniswapSdkError('EVENT_NOT_FOUND', 'Mint receipt did not create a position NFT for the reviewed recipient');\n}\n\n/** Reduces only same-manager, same-position, same-recipient receipt evidence. */\nexport function summarizeV3PositionReceipt(input: {\n logs: readonly V3ReceiptLog[]; manager: Address; tokenId: bigint; recipient: Address;\n}): V3PositionReceiptEvidence {\n const evidence: V3PositionReceiptEvidence = {\n liquidityAdded: 0n,\n amount0Added: 0n,\n amount1Added: 0n,\n liquidityRemoved: 0n,\n amount0Collected: 0n,\n amount1Collected: 0n,\n burned: false,\n };\n for (const log of input.logs) {\n if (log.address.toLowerCase() !== input.manager.toLowerCase()) continue;\n try {\n const decoded = decodeEventLog({ abi: v3PositionManagerEventAbi, data: log.data, topics: decodableTopics(log.topics) }) as PositionManagerEvent;\n if (decoded.args.tokenId !== input.tokenId) continue;\n if (decoded.eventName === 'IncreaseLiquidity') {\n evidence.liquidityAdded += decoded.args.liquidity;\n evidence.amount0Added += decoded.args.amount0;\n evidence.amount1Added += decoded.args.amount1;\n } else if (decoded.eventName === 'DecreaseLiquidity') {\n evidence.liquidityRemoved += decoded.args.liquidity;\n } else if (decoded.eventName === 'Collect' && decoded.args.recipient.toLowerCase() === input.recipient.toLowerCase()) {\n evidence.amount0Collected += decoded.args.amount0;\n evidence.amount1Collected += decoded.args.amount1;\n } else if (decoded.eventName === 'Transfer'\n && decoded.args.from.toLowerCase() === input.recipient.toLowerCase()\n && decoded.args.to === zeroAddress) {\n evidence.burned = true;\n }\n } catch {\n // Unrelated or malformed manager logs do not contribute evidence.\n }\n }\n return evidence;\n}\n"]}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type Address, type Hex } from 'viem';
|
|
2
|
+
export type V3TransactionMaterial = {
|
|
3
|
+
to: Address;
|
|
4
|
+
data: Hex;
|
|
5
|
+
value: 0n;
|
|
6
|
+
};
|
|
7
|
+
export type V3PositionManagerMulticallMaterial = V3TransactionMaterial & {
|
|
8
|
+
calls: readonly Hex[];
|
|
9
|
+
};
|
|
10
|
+
export type V3AtomicCall = {
|
|
11
|
+
target: Address;
|
|
12
|
+
allowFailure: boolean;
|
|
13
|
+
callData: Hex;
|
|
14
|
+
};
|
|
15
|
+
export type V3AtomicPoolInitializationMaterial = V3TransactionMaterial & {
|
|
16
|
+
calls: readonly V3AtomicCall[];
|
|
17
|
+
};
|
|
18
|
+
export type V3MintParams = {
|
|
19
|
+
token0: Address;
|
|
20
|
+
token1: Address;
|
|
21
|
+
fee: number;
|
|
22
|
+
tickLower: number;
|
|
23
|
+
tickUpper: number;
|
|
24
|
+
amount0Desired: bigint;
|
|
25
|
+
amount1Desired: bigint;
|
|
26
|
+
amount0Min: bigint;
|
|
27
|
+
amount1Min: bigint;
|
|
28
|
+
recipient: Address;
|
|
29
|
+
deadline: bigint;
|
|
30
|
+
};
|
|
31
|
+
export type V3IncreaseLiquidityParams = {
|
|
32
|
+
tokenId: bigint;
|
|
33
|
+
amount0Desired: bigint;
|
|
34
|
+
amount1Desired: bigint;
|
|
35
|
+
amount0Min: bigint;
|
|
36
|
+
amount1Min: bigint;
|
|
37
|
+
deadline: bigint;
|
|
38
|
+
};
|
|
39
|
+
export type V3DecreaseLiquidityParams = {
|
|
40
|
+
tokenId: bigint;
|
|
41
|
+
liquidity: bigint;
|
|
42
|
+
amount0Min: bigint;
|
|
43
|
+
amount1Min: bigint;
|
|
44
|
+
deadline: bigint;
|
|
45
|
+
};
|
|
46
|
+
export declare function buildV3ApprovalTransaction(token: Address, manager: Address, amount: bigint): V3TransactionMaterial;
|
|
47
|
+
export declare function buildV3AtomicPoolInitializationTransaction(input: {
|
|
48
|
+
multicall: Address;
|
|
49
|
+
factory: Address;
|
|
50
|
+
manager: Address;
|
|
51
|
+
token0: Address;
|
|
52
|
+
token1: Address;
|
|
53
|
+
fee: number;
|
|
54
|
+
sqrtPriceX96: bigint;
|
|
55
|
+
}): V3AtomicPoolInitializationMaterial;
|
|
56
|
+
export declare function buildV3MintPositionTransaction(input: {
|
|
57
|
+
manager: Address;
|
|
58
|
+
params: V3MintParams;
|
|
59
|
+
initialize?: {
|
|
60
|
+
sqrtPriceX96: bigint;
|
|
61
|
+
};
|
|
62
|
+
}): V3PositionManagerMulticallMaterial;
|
|
63
|
+
export declare function buildV3CollectTransaction(input: {
|
|
64
|
+
manager: Address;
|
|
65
|
+
tokenId: bigint;
|
|
66
|
+
recipient: Address;
|
|
67
|
+
}): V3TransactionMaterial;
|
|
68
|
+
export declare function buildV3IncreaseLiquidityTransaction(input: {
|
|
69
|
+
manager: Address;
|
|
70
|
+
params: V3IncreaseLiquidityParams;
|
|
71
|
+
}): V3TransactionMaterial;
|
|
72
|
+
export declare function buildV3DecreaseAndCollectTransaction(input: {
|
|
73
|
+
manager: Address;
|
|
74
|
+
recipient: Address;
|
|
75
|
+
tokenId: bigint;
|
|
76
|
+
decrease?: V3DecreaseLiquidityParams;
|
|
77
|
+
burn?: boolean;
|
|
78
|
+
}): V3PositionManagerMulticallMaterial;
|
|
79
|
+
export declare function buildV3CompoundTransaction(input: {
|
|
80
|
+
manager: Address;
|
|
81
|
+
recipient: Address;
|
|
82
|
+
params: V3IncreaseLiquidityParams;
|
|
83
|
+
}): V3PositionManagerMulticallMaterial;
|
|
84
|
+
export declare function reviewV3ApprovalCalldata(data: Hex, manager: Address): bigint;
|
|
85
|
+
export declare function reviewV3AtomicPoolInitializationCalldata(data: Hex, expected: {
|
|
86
|
+
factory: Address;
|
|
87
|
+
manager: Address;
|
|
88
|
+
token0: Address;
|
|
89
|
+
token1: Address;
|
|
90
|
+
fee?: number;
|
|
91
|
+
sqrtPriceX96?: bigint;
|
|
92
|
+
}): void;
|
|
93
|
+
export declare function reviewV3MintPositionCalldata(data: Hex, expected: {
|
|
94
|
+
token0: Address;
|
|
95
|
+
token1: Address;
|
|
96
|
+
recipient: Address;
|
|
97
|
+
}): V3MintParams;
|
|
98
|
+
export type ReviewedV3CloseCalldata = {
|
|
99
|
+
liquidityRemoved: bigint;
|
|
100
|
+
burned: boolean;
|
|
101
|
+
};
|
|
102
|
+
export declare function reviewV3LiquidityRemovalCalldata(data: Hex, recipient: Address, tokenId: bigint): bigint;
|
|
103
|
+
export declare function reviewV3CloseCalldata(data: Hex, recipient: Address, tokenId: bigint): ReviewedV3CloseCalldata;
|
|
104
|
+
export declare function reviewV3IncreaseLiquidityCalldata(data: Hex, tokenId: bigint): V3IncreaseLiquidityParams;
|
|
105
|
+
export declare function reviewV3CollectCalldata(data: Hex, recipient: Address, tokenId: bigint): void;
|
|
106
|
+
export declare function reviewV3CompoundCalldata(data: Hex, recipient: Address, tokenId: bigint): void;
|
|
107
|
+
//# sourceMappingURL=v3-transactions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-transactions.d.ts","sourceRoot":"","sources":["../src/v3-transactions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { decodeFunctionData, encodeFunctionData, getAddress } from 'viem';
|
|
2
|
+
import { UniswapSdkError } from './errors.js';
|
|
3
|
+
import { multicall3Abi, V3_MAX_UINT128, v3Erc20Abi, v3FactoryAbi, v3PositionManagerAbi } from './v3-abis.js';
|
|
4
|
+
function invalid(message) {
|
|
5
|
+
throw new UniswapSdkError('INVALID_ARGUMENT', message);
|
|
6
|
+
}
|
|
7
|
+
function mismatch(message) {
|
|
8
|
+
throw new UniswapSdkError('CALLDATA_MISMATCH', message);
|
|
9
|
+
}
|
|
10
|
+
function same(left, right) {
|
|
11
|
+
return left.toLowerCase() === right.toLowerCase();
|
|
12
|
+
}
|
|
13
|
+
function checkedAddress(value, label) {
|
|
14
|
+
try {
|
|
15
|
+
return getAddress(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return invalid(`${label} must be a valid EVM address`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function uint(value, bits, label, allowZero = true) {
|
|
22
|
+
if (typeof value !== 'bigint' || value < (allowZero ? 0n : 1n) || value >= 1n << BigInt(bits)) {
|
|
23
|
+
invalid(`${label} must be ${allowZero ? '' : 'positive '}uint${bits}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function fee(value) {
|
|
27
|
+
if (!Number.isInteger(value) || value < 0 || value >= 2 ** 24)
|
|
28
|
+
invalid('Fee must be uint24');
|
|
29
|
+
}
|
|
30
|
+
function validateIncrease(params) {
|
|
31
|
+
uint(params.tokenId, 256, 'Position token ID', false);
|
|
32
|
+
uint(params.amount0Desired, 256, 'Token 0 desired amount');
|
|
33
|
+
uint(params.amount1Desired, 256, 'Token 1 desired amount');
|
|
34
|
+
uint(params.amount0Min, 256, 'Token 0 minimum amount');
|
|
35
|
+
uint(params.amount1Min, 256, 'Token 1 minimum amount');
|
|
36
|
+
uint(params.deadline, 256, 'Deadline', false);
|
|
37
|
+
if (params.amount0Desired === 0n && params.amount1Desired === 0n)
|
|
38
|
+
invalid('Liquidity increase must include a desired token amount');
|
|
39
|
+
if (params.amount0Min > params.amount0Desired || params.amount1Min > params.amount1Desired)
|
|
40
|
+
invalid('Liquidity minimums cannot exceed desired amounts');
|
|
41
|
+
}
|
|
42
|
+
export function buildV3ApprovalTransaction(token, manager, amount) {
|
|
43
|
+
uint(amount, 256, 'Approval amount', false);
|
|
44
|
+
return { to: checkedAddress(token, 'Token'), data: encodeFunctionData({ abi: v3Erc20Abi, functionName: 'approve', args: [checkedAddress(manager, 'Position manager'), amount] }), value: 0n };
|
|
45
|
+
}
|
|
46
|
+
export function buildV3AtomicPoolInitializationTransaction(input) {
|
|
47
|
+
const factory = checkedAddress(input.factory, 'Factory');
|
|
48
|
+
const manager = checkedAddress(input.manager, 'Position manager');
|
|
49
|
+
const token0 = checkedAddress(input.token0, 'Token 0');
|
|
50
|
+
const token1 = checkedAddress(input.token1, 'Token 1');
|
|
51
|
+
if (same(token0, token1))
|
|
52
|
+
invalid('Pool tokens must be distinct');
|
|
53
|
+
fee(input.fee);
|
|
54
|
+
uint(input.sqrtPriceX96, 160, 'Initial square-root price', false);
|
|
55
|
+
const calls = [{
|
|
56
|
+
target: factory,
|
|
57
|
+
allowFailure: false,
|
|
58
|
+
callData: encodeFunctionData({ abi: v3FactoryAbi, functionName: 'createPool', args: [token0, token1, input.fee] }),
|
|
59
|
+
}, {
|
|
60
|
+
target: manager,
|
|
61
|
+
allowFailure: false,
|
|
62
|
+
callData: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'createAndInitializePoolIfNecessary', args: [token0, token1, input.fee, input.sqrtPriceX96] }),
|
|
63
|
+
}];
|
|
64
|
+
return { to: checkedAddress(input.multicall, 'Multicall'), data: encodeFunctionData({ abi: multicall3Abi, functionName: 'aggregate3', args: [calls] }), value: 0n, calls };
|
|
65
|
+
}
|
|
66
|
+
export function buildV3MintPositionTransaction(input) {
|
|
67
|
+
const manager = checkedAddress(input.manager, 'Position manager');
|
|
68
|
+
const params = { ...input.params, token0: checkedAddress(input.params.token0, 'Token 0'), token1: checkedAddress(input.params.token1, 'Token 1'), recipient: checkedAddress(input.params.recipient, 'Recipient') };
|
|
69
|
+
if (same(params.token0, params.token1))
|
|
70
|
+
invalid('Mint tokens must be distinct');
|
|
71
|
+
fee(params.fee);
|
|
72
|
+
if (!Number.isInteger(params.tickLower) || !Number.isInteger(params.tickUpper) || params.tickLower < -887272 || params.tickUpper > 887272 || params.tickLower >= params.tickUpper)
|
|
73
|
+
invalid('Mint ticks must be ordered integers in the Uniswap v3 tick range');
|
|
74
|
+
uint(params.amount0Desired, 256, 'Token 0 desired amount');
|
|
75
|
+
uint(params.amount1Desired, 256, 'Token 1 desired amount');
|
|
76
|
+
uint(params.amount0Min, 256, 'Token 0 minimum amount');
|
|
77
|
+
uint(params.amount1Min, 256, 'Token 1 minimum amount');
|
|
78
|
+
uint(params.deadline, 256, 'Deadline', false);
|
|
79
|
+
if (params.amount0Desired === 0n && params.amount1Desired === 0n)
|
|
80
|
+
invalid('Mint must include a desired token amount');
|
|
81
|
+
if (params.amount0Min > params.amount0Desired || params.amount1Min > params.amount1Desired)
|
|
82
|
+
invalid('Mint minimums cannot exceed desired amounts');
|
|
83
|
+
if (input.initialize)
|
|
84
|
+
uint(input.initialize.sqrtPriceX96, 160, 'Initial square-root price', false);
|
|
85
|
+
const mint = encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'mint', args: [params] });
|
|
86
|
+
const calls = input.initialize
|
|
87
|
+
? [encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'createAndInitializePoolIfNecessary', args: [params.token0, params.token1, params.fee, input.initialize.sqrtPriceX96] }), mint]
|
|
88
|
+
: [mint];
|
|
89
|
+
return { to: manager, data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'multicall', args: [calls] }), value: 0n, calls };
|
|
90
|
+
}
|
|
91
|
+
export function buildV3CollectTransaction(input) {
|
|
92
|
+
uint(input.tokenId, 256, 'Position token ID', false);
|
|
93
|
+
return {
|
|
94
|
+
to: checkedAddress(input.manager, 'Position manager'),
|
|
95
|
+
data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'collect', args: [{ tokenId: input.tokenId, recipient: checkedAddress(input.recipient, 'Recipient'), amount0Max: V3_MAX_UINT128, amount1Max: V3_MAX_UINT128 }] }),
|
|
96
|
+
value: 0n,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function buildV3IncreaseLiquidityTransaction(input) {
|
|
100
|
+
validateIncrease(input.params);
|
|
101
|
+
return { to: checkedAddress(input.manager, 'Position manager'), data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'increaseLiquidity', args: [input.params] }), value: 0n };
|
|
102
|
+
}
|
|
103
|
+
export function buildV3DecreaseAndCollectTransaction(input) {
|
|
104
|
+
const calls = [];
|
|
105
|
+
uint(input.tokenId, 256, 'Position token ID', false);
|
|
106
|
+
if (input.decrease) {
|
|
107
|
+
uint(input.decrease.tokenId, 256, 'Decrease position token ID', false);
|
|
108
|
+
uint(input.decrease.liquidity, 128, 'Liquidity decrease', false);
|
|
109
|
+
uint(input.decrease.amount0Min, 256, 'Token 0 minimum amount');
|
|
110
|
+
uint(input.decrease.amount1Min, 256, 'Token 1 minimum amount');
|
|
111
|
+
uint(input.decrease.deadline, 256, 'Deadline', false);
|
|
112
|
+
calls.push(encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'decreaseLiquidity', args: [input.decrease] }));
|
|
113
|
+
}
|
|
114
|
+
if (input.decrease && input.decrease.tokenId !== input.tokenId)
|
|
115
|
+
invalid('Liquidity decrease targets a different position');
|
|
116
|
+
calls.push(buildV3CollectTransaction({ manager: input.manager, tokenId: input.tokenId, recipient: input.recipient }).data);
|
|
117
|
+
if (input.burn)
|
|
118
|
+
calls.push(encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'burn', args: [input.tokenId] }));
|
|
119
|
+
return { to: checkedAddress(input.manager, 'Position manager'), data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'multicall', args: [calls] }), value: 0n, calls };
|
|
120
|
+
}
|
|
121
|
+
export function buildV3CompoundTransaction(input) {
|
|
122
|
+
validateIncrease(input.params);
|
|
123
|
+
const collect = buildV3CollectTransaction({ manager: input.manager, tokenId: input.params.tokenId, recipient: input.recipient }).data;
|
|
124
|
+
const increase = buildV3IncreaseLiquidityTransaction({ manager: input.manager, params: input.params }).data;
|
|
125
|
+
const calls = [collect, increase];
|
|
126
|
+
return { to: checkedAddress(input.manager, 'Position manager'), data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'multicall', args: [calls] }), value: 0n, calls };
|
|
127
|
+
}
|
|
128
|
+
export function reviewV3ApprovalCalldata(data, manager) {
|
|
129
|
+
try {
|
|
130
|
+
const decoded = decodeFunctionData({ abi: v3Erc20Abi, data });
|
|
131
|
+
if (decoded.functionName !== 'approve' || !same(decoded.args[0], manager) || decoded.args[1] <= 0n)
|
|
132
|
+
mismatch('Approval calldata does not authorize the reviewed position manager');
|
|
133
|
+
return decoded.args[1];
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (error instanceof UniswapSdkError)
|
|
137
|
+
throw error;
|
|
138
|
+
return mismatch('Approval calldata is not a reviewed ERC-20 approval');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export function reviewV3AtomicPoolInitializationCalldata(data, expected) {
|
|
142
|
+
try {
|
|
143
|
+
const decoded = decodeFunctionData({ abi: multicall3Abi, data });
|
|
144
|
+
if (decoded.functionName !== 'aggregate3' || decoded.args[0].length !== 2 || decoded.args[0].some(call => call.allowFailure))
|
|
145
|
+
mismatch('Pool initialization is not a fail-closed two-call batch');
|
|
146
|
+
const [factoryEnvelope, managerEnvelope] = decoded.args[0];
|
|
147
|
+
const factoryCall = decodeFunctionData({ abi: v3FactoryAbi, data: factoryEnvelope.callData });
|
|
148
|
+
const managerCall = decodeFunctionData({ abi: v3PositionManagerAbi, data: managerEnvelope.callData });
|
|
149
|
+
if (!same(factoryEnvelope.target, expected.factory) || factoryCall.functionName !== 'createPool')
|
|
150
|
+
mismatch('Pool initialization does not use the reviewed factory');
|
|
151
|
+
if (!same(managerEnvelope.target, expected.manager) || managerCall.functionName !== 'createAndInitializePoolIfNecessary')
|
|
152
|
+
mismatch('Pool initialization does not use the reviewed position manager');
|
|
153
|
+
const pair = [expected.token0.toLowerCase(), expected.token1.toLowerCase()].sort().join(':');
|
|
154
|
+
if ([factoryCall.args[0].toLowerCase(), factoryCall.args[1].toLowerCase()].sort().join(':') !== pair)
|
|
155
|
+
mismatch('Pool creation terms differ from the reviewed pair');
|
|
156
|
+
if ([managerCall.args[0].toLowerCase(), managerCall.args[1].toLowerCase()].sort().join(':') !== pair || managerCall.args[2] !== factoryCall.args[2])
|
|
157
|
+
mismatch('Pool initialization terms differ from the reviewed pair');
|
|
158
|
+
if (expected.fee !== undefined && factoryCall.args[2] !== expected.fee)
|
|
159
|
+
mismatch('Pool initialization fee differs from the reviewed fee');
|
|
160
|
+
if (expected.sqrtPriceX96 !== undefined && managerCall.args[3] !== expected.sqrtPriceX96)
|
|
161
|
+
mismatch('Pool initialization price differs from the reviewed price');
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (error instanceof UniswapSdkError)
|
|
165
|
+
throw error;
|
|
166
|
+
mismatch('Pool initialization calldata is not a reviewed atomic batch');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
export function reviewV3MintPositionCalldata(data, expected) {
|
|
170
|
+
try {
|
|
171
|
+
const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });
|
|
172
|
+
if (decoded.functionName !== 'multicall')
|
|
173
|
+
mismatch('Mint calldata is not a position-manager multicall');
|
|
174
|
+
const calls = decoded.args[0].map(call => decodeFunctionData({ abi: v3PositionManagerAbi, data: call }));
|
|
175
|
+
if (calls.length < 1 || calls.length > 2)
|
|
176
|
+
mismatch('Mint calldata must contain only an optional pool initialization followed by one mint');
|
|
177
|
+
const mint = calls.at(-1);
|
|
178
|
+
if (!mint || mint.functionName !== 'mint')
|
|
179
|
+
return mismatch('Mint calldata must end with one position mint');
|
|
180
|
+
const params = mint.args[0];
|
|
181
|
+
if (calls.length === 2) {
|
|
182
|
+
const initialization = calls[0];
|
|
183
|
+
if (initialization.functionName !== 'createAndInitializePoolIfNecessary')
|
|
184
|
+
mismatch('Mint calldata contains an unreviewed call before the position mint');
|
|
185
|
+
if (!same(initialization.args[0], params.token0)
|
|
186
|
+
|| !same(initialization.args[1], params.token1)
|
|
187
|
+
|| initialization.args[2] !== params.fee
|
|
188
|
+
|| initialization.args[3] <= 0n)
|
|
189
|
+
mismatch('Mint pool initialization differs from the position mint');
|
|
190
|
+
}
|
|
191
|
+
const expectedPair = [expected.token0.toLowerCase(), expected.token1.toLowerCase()].sort().join(':');
|
|
192
|
+
if ([params.token0.toLowerCase(), params.token1.toLowerCase()].sort().join(':') !== expectedPair)
|
|
193
|
+
mismatch('Mint calldata targets a different token pair');
|
|
194
|
+
if (!same(params.recipient, expected.recipient))
|
|
195
|
+
mismatch('Mint calldata sends the position NFT to a different recipient');
|
|
196
|
+
return params;
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (error instanceof UniswapSdkError)
|
|
200
|
+
throw error;
|
|
201
|
+
return mismatch('Mint calldata contains undecodable position-manager calls');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function reviewLiquidityRemoval(data, recipient, tokenId, allowBurn) {
|
|
205
|
+
let calls;
|
|
206
|
+
try {
|
|
207
|
+
const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });
|
|
208
|
+
if (decoded.functionName !== 'multicall')
|
|
209
|
+
mismatch('Liquidity removal calldata is not a position-manager multicall');
|
|
210
|
+
calls = decoded.args[0];
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
if (error instanceof UniswapSdkError)
|
|
214
|
+
throw error;
|
|
215
|
+
return mismatch('Liquidity removal calldata is not a reviewed position-manager multicall');
|
|
216
|
+
}
|
|
217
|
+
let collected = false;
|
|
218
|
+
let burned = false;
|
|
219
|
+
let liquidityRemoved = 0n;
|
|
220
|
+
for (const [index, call] of calls.entries()) {
|
|
221
|
+
try {
|
|
222
|
+
const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data: call });
|
|
223
|
+
if (decoded.functionName === 'decreaseLiquidity') {
|
|
224
|
+
if (collected || burned)
|
|
225
|
+
mismatch('Uniswap close transaction cannot remove liquidity after collection');
|
|
226
|
+
if (decoded.args[0].tokenId !== tokenId)
|
|
227
|
+
mismatch('Uniswap close transaction targets a different position NFT');
|
|
228
|
+
liquidityRemoved += decoded.args[0].liquidity;
|
|
229
|
+
}
|
|
230
|
+
else if (decoded.functionName === 'collect') {
|
|
231
|
+
const params = decoded.args[0];
|
|
232
|
+
if (collected || burned)
|
|
233
|
+
mismatch('Uniswap close transaction must collect once after all liquidity-removal calls');
|
|
234
|
+
if (params.tokenId !== tokenId)
|
|
235
|
+
mismatch('Uniswap close transaction targets a different position NFT');
|
|
236
|
+
if (!same(params.recipient, recipient))
|
|
237
|
+
mismatch('Uniswap close transaction collects to a different recipient');
|
|
238
|
+
if (params.amount0Max !== V3_MAX_UINT128 || params.amount1Max !== V3_MAX_UINT128)
|
|
239
|
+
mismatch('Uniswap close transaction must collect all released token amounts');
|
|
240
|
+
collected = true;
|
|
241
|
+
}
|
|
242
|
+
else if (decoded.functionName === 'burn') {
|
|
243
|
+
if (!allowBurn)
|
|
244
|
+
mismatch('Uniswap liquidity-removal transaction cannot burn the position NFT');
|
|
245
|
+
if (burned || !collected || index !== calls.length - 1)
|
|
246
|
+
mismatch('Uniswap close transaction must burn once after collection');
|
|
247
|
+
if (decoded.args[0] !== tokenId)
|
|
248
|
+
mismatch('Uniswap close transaction burns a different position NFT');
|
|
249
|
+
burned = true;
|
|
250
|
+
}
|
|
251
|
+
else
|
|
252
|
+
mismatch('Liquidity removal contains an unreviewed position-manager call');
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
if (error instanceof UniswapSdkError)
|
|
256
|
+
throw error;
|
|
257
|
+
mismatch('Liquidity removal contains undecodable position-manager calldata');
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (!collected)
|
|
261
|
+
mismatch('Uniswap close transaction does not collect the reviewed position NFT');
|
|
262
|
+
return { liquidityRemoved, burned };
|
|
263
|
+
}
|
|
264
|
+
export function reviewV3LiquidityRemovalCalldata(data, recipient, tokenId) {
|
|
265
|
+
const reviewed = reviewLiquidityRemoval(data, recipient, tokenId, false);
|
|
266
|
+
if (reviewed.liquidityRemoved === 0n)
|
|
267
|
+
mismatch('Uniswap close transaction does not remove position liquidity');
|
|
268
|
+
return reviewed.liquidityRemoved;
|
|
269
|
+
}
|
|
270
|
+
export function reviewV3CloseCalldata(data, recipient, tokenId) {
|
|
271
|
+
const reviewed = reviewLiquidityRemoval(data, recipient, tokenId, true);
|
|
272
|
+
if (reviewed.liquidityRemoved === 0n && !reviewed.burned)
|
|
273
|
+
mismatch('Uniswap close transaction does not remove position liquidity or burn an empty NFT');
|
|
274
|
+
return reviewed;
|
|
275
|
+
}
|
|
276
|
+
export function reviewV3IncreaseLiquidityCalldata(data, tokenId) {
|
|
277
|
+
try {
|
|
278
|
+
const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });
|
|
279
|
+
if (decoded.functionName !== 'increaseLiquidity')
|
|
280
|
+
mismatch('Uniswap deposit transaction calldata is not a reviewed liquidity increase');
|
|
281
|
+
if (decoded.args[0].tokenId !== tokenId)
|
|
282
|
+
mismatch('Uniswap deposit transaction targets a different position NFT');
|
|
283
|
+
if (decoded.args[0].amount0Desired === 0n && decoded.args[0].amount1Desired === 0n)
|
|
284
|
+
mismatch('Uniswap deposit transaction does not add token amounts');
|
|
285
|
+
return decoded.args[0];
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
if (error instanceof UniswapSdkError)
|
|
289
|
+
throw error;
|
|
290
|
+
return mismatch('Deposit calldata is not a reviewed liquidity increase');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function reviewV3CollectCalldata(data, recipient, tokenId) {
|
|
294
|
+
try {
|
|
295
|
+
const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });
|
|
296
|
+
if (decoded.functionName !== 'collect')
|
|
297
|
+
mismatch('Uniswap fee-claim transaction calldata is not a reviewed collect call');
|
|
298
|
+
if (decoded.args[0].tokenId !== tokenId)
|
|
299
|
+
mismatch('Uniswap fee-claim transaction targets a different position NFT');
|
|
300
|
+
if (!same(decoded.args[0].recipient, recipient))
|
|
301
|
+
mismatch('Uniswap fee-claim transaction collects to a different recipient');
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
if (error instanceof UniswapSdkError)
|
|
305
|
+
throw error;
|
|
306
|
+
mismatch('Fee-claim calldata is not a reviewed collect call');
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
export function reviewV3CompoundCalldata(data, recipient, tokenId) {
|
|
310
|
+
try {
|
|
311
|
+
const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });
|
|
312
|
+
if (decoded.functionName !== 'multicall' || decoded.args[0].length !== 2)
|
|
313
|
+
mismatch('Compound calldata must contain exactly collect and increase calls');
|
|
314
|
+
reviewV3CollectCalldata(decoded.args[0][0], recipient, tokenId);
|
|
315
|
+
reviewV3IncreaseLiquidityCalldata(decoded.args[0][1], tokenId);
|
|
316
|
+
}
|
|
317
|
+
catch (error) {
|
|
318
|
+
if (error instanceof UniswapSdkError)
|
|
319
|
+
throw error;
|
|
320
|
+
mismatch('Compound calldata is not a reviewed position-manager multicall');
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=v3-transactions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3-transactions.js","sourceRoot":"","sources":["../src/v3-transactions.ts"],"names":[],"mappings":"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","sourcesContent":["import { decodeFunctionData, encodeFunctionData, getAddress, type Address, type Hex } from 'viem';\nimport { UniswapSdkError } from './errors.js';\nimport { multicall3Abi, V3_MAX_UINT128, v3Erc20Abi, v3FactoryAbi, v3PositionManagerAbi } from './v3-abis.js';\n\nexport type V3TransactionMaterial = { to: Address; data: Hex; value: 0n };\nexport type V3PositionManagerMulticallMaterial = V3TransactionMaterial & { calls: readonly Hex[] };\nexport type V3AtomicCall = { target: Address; allowFailure: boolean; callData: Hex };\nexport type V3AtomicPoolInitializationMaterial = V3TransactionMaterial & { calls: readonly V3AtomicCall[] };\n\nexport type V3MintParams = {\n token0: Address; token1: Address; fee: number; tickLower: number; tickUpper: number;\n amount0Desired: bigint; amount1Desired: bigint; amount0Min: bigint; amount1Min: bigint;\n recipient: Address; deadline: bigint;\n};\n\nexport type V3IncreaseLiquidityParams = {\n tokenId: bigint; amount0Desired: bigint; amount1Desired: bigint;\n amount0Min: bigint; amount1Min: bigint; deadline: bigint;\n};\n\nexport type V3DecreaseLiquidityParams = {\n tokenId: bigint; liquidity: bigint; amount0Min: bigint; amount1Min: bigint; deadline: bigint;\n};\n\nfunction invalid(message: string): never {\n throw new UniswapSdkError('INVALID_ARGUMENT', message);\n}\n\nfunction mismatch(message: string): never {\n throw new UniswapSdkError('CALLDATA_MISMATCH', message);\n}\n\nfunction same(left: string, right: string): boolean {\n return left.toLowerCase() === right.toLowerCase();\n}\n\nfunction checkedAddress(value: Address, label: string): Address {\n try { return getAddress(value); }\n catch { return invalid(`${label} must be a valid EVM address`); }\n}\n\nfunction uint(value: bigint, bits: number, label: string, allowZero = true): void {\n if (typeof value !== 'bigint' || value < (allowZero ? 0n : 1n) || value >= 1n << BigInt(bits)) {\n invalid(`${label} must be ${allowZero ? '' : 'positive '}uint${bits}`);\n }\n}\n\nfunction fee(value: number): void {\n if (!Number.isInteger(value) || value < 0 || value >= 2 ** 24) invalid('Fee must be uint24');\n}\n\nfunction validateIncrease(params: V3IncreaseLiquidityParams): void {\n uint(params.tokenId, 256, 'Position token ID', false);\n uint(params.amount0Desired, 256, 'Token 0 desired amount');\n uint(params.amount1Desired, 256, 'Token 1 desired amount');\n uint(params.amount0Min, 256, 'Token 0 minimum amount');\n uint(params.amount1Min, 256, 'Token 1 minimum amount');\n uint(params.deadline, 256, 'Deadline', false);\n if (params.amount0Desired === 0n && params.amount1Desired === 0n) invalid('Liquidity increase must include a desired token amount');\n if (params.amount0Min > params.amount0Desired || params.amount1Min > params.amount1Desired) invalid('Liquidity minimums cannot exceed desired amounts');\n}\n\nexport function buildV3ApprovalTransaction(token: Address, manager: Address, amount: bigint): V3TransactionMaterial {\n uint(amount, 256, 'Approval amount', false);\n return { to: checkedAddress(token, 'Token'), data: encodeFunctionData({ abi: v3Erc20Abi, functionName: 'approve', args: [checkedAddress(manager, 'Position manager'), amount] }), value: 0n };\n}\n\nexport function buildV3AtomicPoolInitializationTransaction(input: {\n multicall: Address; factory: Address; manager: Address; token0: Address; token1: Address;\n fee: number; sqrtPriceX96: bigint;\n}): V3AtomicPoolInitializationMaterial {\n const factory = checkedAddress(input.factory, 'Factory');\n const manager = checkedAddress(input.manager, 'Position manager');\n const token0 = checkedAddress(input.token0, 'Token 0');\n const token1 = checkedAddress(input.token1, 'Token 1');\n if (same(token0, token1)) invalid('Pool tokens must be distinct');\n fee(input.fee);\n uint(input.sqrtPriceX96, 160, 'Initial square-root price', false);\n const calls = [{\n target: factory,\n allowFailure: false,\n callData: encodeFunctionData({ abi: v3FactoryAbi, functionName: 'createPool', args: [token0, token1, input.fee] }),\n }, {\n target: manager,\n allowFailure: false,\n callData: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'createAndInitializePoolIfNecessary', args: [token0, token1, input.fee, input.sqrtPriceX96] }),\n }] as const;\n return { to: checkedAddress(input.multicall, 'Multicall'), data: encodeFunctionData({ abi: multicall3Abi, functionName: 'aggregate3', args: [calls] }), value: 0n, calls };\n}\n\nexport function buildV3MintPositionTransaction(input: {\n manager: Address; params: V3MintParams; initialize?: { sqrtPriceX96: bigint };\n}): V3PositionManagerMulticallMaterial {\n const manager = checkedAddress(input.manager, 'Position manager');\n const params = { ...input.params, token0: checkedAddress(input.params.token0, 'Token 0'), token1: checkedAddress(input.params.token1, 'Token 1'), recipient: checkedAddress(input.params.recipient, 'Recipient') };\n if (same(params.token0, params.token1)) invalid('Mint tokens must be distinct');\n fee(params.fee);\n if (!Number.isInteger(params.tickLower) || !Number.isInteger(params.tickUpper) || params.tickLower < -887272 || params.tickUpper > 887272 || params.tickLower >= params.tickUpper) invalid('Mint ticks must be ordered integers in the Uniswap v3 tick range');\n uint(params.amount0Desired, 256, 'Token 0 desired amount');\n uint(params.amount1Desired, 256, 'Token 1 desired amount');\n uint(params.amount0Min, 256, 'Token 0 minimum amount');\n uint(params.amount1Min, 256, 'Token 1 minimum amount');\n uint(params.deadline, 256, 'Deadline', false);\n if (params.amount0Desired === 0n && params.amount1Desired === 0n) invalid('Mint must include a desired token amount');\n if (params.amount0Min > params.amount0Desired || params.amount1Min > params.amount1Desired) invalid('Mint minimums cannot exceed desired amounts');\n if (input.initialize) uint(input.initialize.sqrtPriceX96, 160, 'Initial square-root price', false);\n const mint = encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'mint', args: [params] });\n const calls = input.initialize\n ? [encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'createAndInitializePoolIfNecessary', args: [params.token0, params.token1, params.fee, input.initialize.sqrtPriceX96] }), mint]\n : [mint];\n return { to: manager, data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'multicall', args: [calls] }), value: 0n, calls };\n}\n\nexport function buildV3CollectTransaction(input: { manager: Address; tokenId: bigint; recipient: Address }): V3TransactionMaterial {\n uint(input.tokenId, 256, 'Position token ID', false);\n return {\n to: checkedAddress(input.manager, 'Position manager'),\n data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'collect', args: [{ tokenId: input.tokenId, recipient: checkedAddress(input.recipient, 'Recipient'), amount0Max: V3_MAX_UINT128, amount1Max: V3_MAX_UINT128 }] }),\n value: 0n,\n };\n}\n\nexport function buildV3IncreaseLiquidityTransaction(input: { manager: Address; params: V3IncreaseLiquidityParams }): V3TransactionMaterial {\n validateIncrease(input.params);\n return { to: checkedAddress(input.manager, 'Position manager'), data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'increaseLiquidity', args: [input.params] }), value: 0n };\n}\n\nexport function buildV3DecreaseAndCollectTransaction(input: {\n manager: Address; recipient: Address; tokenId: bigint; decrease?: V3DecreaseLiquidityParams; burn?: boolean;\n}): V3PositionManagerMulticallMaterial {\n const calls: Hex[] = [];\n uint(input.tokenId, 256, 'Position token ID', false);\n if (input.decrease) {\n uint(input.decrease.tokenId, 256, 'Decrease position token ID', false);\n uint(input.decrease.liquidity, 128, 'Liquidity decrease', false);\n uint(input.decrease.amount0Min, 256, 'Token 0 minimum amount');\n uint(input.decrease.amount1Min, 256, 'Token 1 minimum amount');\n uint(input.decrease.deadline, 256, 'Deadline', false);\n calls.push(encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'decreaseLiquidity', args: [input.decrease] }));\n }\n if (input.decrease && input.decrease.tokenId !== input.tokenId) invalid('Liquidity decrease targets a different position');\n calls.push(buildV3CollectTransaction({ manager: input.manager, tokenId: input.tokenId, recipient: input.recipient }).data);\n if (input.burn) calls.push(encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'burn', args: [input.tokenId] }));\n return { to: checkedAddress(input.manager, 'Position manager'), data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'multicall', args: [calls] }), value: 0n, calls };\n}\n\nexport function buildV3CompoundTransaction(input: {\n manager: Address; recipient: Address; params: V3IncreaseLiquidityParams;\n}): V3PositionManagerMulticallMaterial {\n validateIncrease(input.params);\n const collect = buildV3CollectTransaction({ manager: input.manager, tokenId: input.params.tokenId, recipient: input.recipient }).data;\n const increase = buildV3IncreaseLiquidityTransaction({ manager: input.manager, params: input.params }).data;\n const calls = [collect, increase] as const;\n return { to: checkedAddress(input.manager, 'Position manager'), data: encodeFunctionData({ abi: v3PositionManagerAbi, functionName: 'multicall', args: [calls] }), value: 0n, calls };\n}\n\nexport function reviewV3ApprovalCalldata(data: Hex, manager: Address): bigint {\n try {\n const decoded = decodeFunctionData({ abi: v3Erc20Abi, data });\n if (decoded.functionName !== 'approve' || !same(decoded.args[0], manager) || decoded.args[1] <= 0n) mismatch('Approval calldata does not authorize the reviewed position manager');\n return decoded.args[1];\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n return mismatch('Approval calldata is not a reviewed ERC-20 approval');\n }\n}\n\nexport function reviewV3AtomicPoolInitializationCalldata(data: Hex, expected: {\n factory: Address; manager: Address; token0: Address; token1: Address; fee?: number; sqrtPriceX96?: bigint;\n}): void {\n try {\n const decoded = decodeFunctionData({ abi: multicall3Abi, data });\n if (decoded.functionName !== 'aggregate3' || decoded.args[0].length !== 2 || decoded.args[0].some(call => call.allowFailure)) mismatch('Pool initialization is not a fail-closed two-call batch');\n const [factoryEnvelope, managerEnvelope] = decoded.args[0];\n const factoryCall = decodeFunctionData({ abi: v3FactoryAbi, data: factoryEnvelope.callData });\n const managerCall = decodeFunctionData({ abi: v3PositionManagerAbi, data: managerEnvelope.callData });\n if (!same(factoryEnvelope.target, expected.factory) || factoryCall.functionName !== 'createPool') mismatch('Pool initialization does not use the reviewed factory');\n if (!same(managerEnvelope.target, expected.manager) || managerCall.functionName !== 'createAndInitializePoolIfNecessary') mismatch('Pool initialization does not use the reviewed position manager');\n const pair = [expected.token0.toLowerCase(), expected.token1.toLowerCase()].sort().join(':');\n if ([factoryCall.args[0].toLowerCase(), factoryCall.args[1].toLowerCase()].sort().join(':') !== pair) mismatch('Pool creation terms differ from the reviewed pair');\n if ([managerCall.args[0].toLowerCase(), managerCall.args[1].toLowerCase()].sort().join(':') !== pair || managerCall.args[2] !== factoryCall.args[2]) mismatch('Pool initialization terms differ from the reviewed pair');\n if (expected.fee !== undefined && factoryCall.args[2] !== expected.fee) mismatch('Pool initialization fee differs from the reviewed fee');\n if (expected.sqrtPriceX96 !== undefined && managerCall.args[3] !== expected.sqrtPriceX96) mismatch('Pool initialization price differs from the reviewed price');\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n mismatch('Pool initialization calldata is not a reviewed atomic batch');\n }\n}\n\nexport function reviewV3MintPositionCalldata(data: Hex, expected: {\n token0: Address; token1: Address; recipient: Address;\n}): V3MintParams {\n try {\n const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });\n if (decoded.functionName !== 'multicall') mismatch('Mint calldata is not a position-manager multicall');\n const calls = decoded.args[0].map(call => decodeFunctionData({ abi: v3PositionManagerAbi, data: call }));\n if (calls.length < 1 || calls.length > 2) mismatch('Mint calldata must contain only an optional pool initialization followed by one mint');\n const mint = calls.at(-1);\n if (!mint || mint.functionName !== 'mint') return mismatch('Mint calldata must end with one position mint');\n const params = mint.args[0];\n if (calls.length === 2) {\n const initialization = calls[0];\n if (initialization.functionName !== 'createAndInitializePoolIfNecessary') mismatch('Mint calldata contains an unreviewed call before the position mint');\n if (!same(initialization.args[0], params.token0)\n || !same(initialization.args[1], params.token1)\n || initialization.args[2] !== params.fee\n || initialization.args[3] <= 0n) mismatch('Mint pool initialization differs from the position mint');\n }\n const expectedPair = [expected.token0.toLowerCase(), expected.token1.toLowerCase()].sort().join(':');\n if ([params.token0.toLowerCase(), params.token1.toLowerCase()].sort().join(':') !== expectedPair) mismatch('Mint calldata targets a different token pair');\n if (!same(params.recipient, expected.recipient)) mismatch('Mint calldata sends the position NFT to a different recipient');\n return params;\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n return mismatch('Mint calldata contains undecodable position-manager calls');\n }\n}\n\nexport type ReviewedV3CloseCalldata = { liquidityRemoved: bigint; burned: boolean };\n\nfunction reviewLiquidityRemoval(data: Hex, recipient: Address, tokenId: bigint, allowBurn: boolean): ReviewedV3CloseCalldata {\n let calls: readonly Hex[];\n try {\n const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });\n if (decoded.functionName !== 'multicall') mismatch('Liquidity removal calldata is not a position-manager multicall');\n calls = decoded.args[0];\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n return mismatch('Liquidity removal calldata is not a reviewed position-manager multicall');\n }\n let collected = false; let burned = false; let liquidityRemoved = 0n;\n for (const [index, call] of calls.entries()) {\n try {\n const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data: call });\n if (decoded.functionName === 'decreaseLiquidity') {\n if (collected || burned) mismatch('Uniswap close transaction cannot remove liquidity after collection');\n if (decoded.args[0].tokenId !== tokenId) mismatch('Uniswap close transaction targets a different position NFT');\n liquidityRemoved += decoded.args[0].liquidity;\n } else if (decoded.functionName === 'collect') {\n const params = decoded.args[0];\n if (collected || burned) mismatch('Uniswap close transaction must collect once after all liquidity-removal calls');\n if (params.tokenId !== tokenId) mismatch('Uniswap close transaction targets a different position NFT');\n if (!same(params.recipient, recipient)) mismatch('Uniswap close transaction collects to a different recipient');\n if (params.amount0Max !== V3_MAX_UINT128 || params.amount1Max !== V3_MAX_UINT128) mismatch('Uniswap close transaction must collect all released token amounts');\n collected = true;\n } else if (decoded.functionName === 'burn') {\n if (!allowBurn) mismatch('Uniswap liquidity-removal transaction cannot burn the position NFT');\n if (burned || !collected || index !== calls.length - 1) mismatch('Uniswap close transaction must burn once after collection');\n if (decoded.args[0] !== tokenId) mismatch('Uniswap close transaction burns a different position NFT');\n burned = true;\n } else mismatch('Liquidity removal contains an unreviewed position-manager call');\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n mismatch('Liquidity removal contains undecodable position-manager calldata');\n }\n }\n if (!collected) mismatch('Uniswap close transaction does not collect the reviewed position NFT');\n return { liquidityRemoved, burned };\n}\n\nexport function reviewV3LiquidityRemovalCalldata(data: Hex, recipient: Address, tokenId: bigint): bigint {\n const reviewed = reviewLiquidityRemoval(data, recipient, tokenId, false);\n if (reviewed.liquidityRemoved === 0n) mismatch('Uniswap close transaction does not remove position liquidity');\n return reviewed.liquidityRemoved;\n}\n\nexport function reviewV3CloseCalldata(data: Hex, recipient: Address, tokenId: bigint): ReviewedV3CloseCalldata {\n const reviewed = reviewLiquidityRemoval(data, recipient, tokenId, true);\n if (reviewed.liquidityRemoved === 0n && !reviewed.burned) mismatch('Uniswap close transaction does not remove position liquidity or burn an empty NFT');\n return reviewed;\n}\n\nexport function reviewV3IncreaseLiquidityCalldata(data: Hex, tokenId: bigint): V3IncreaseLiquidityParams {\n try {\n const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });\n if (decoded.functionName !== 'increaseLiquidity') mismatch('Uniswap deposit transaction calldata is not a reviewed liquidity increase');\n if (decoded.args[0].tokenId !== tokenId) mismatch('Uniswap deposit transaction targets a different position NFT');\n if (decoded.args[0].amount0Desired === 0n && decoded.args[0].amount1Desired === 0n) mismatch('Uniswap deposit transaction does not add token amounts');\n return decoded.args[0];\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n return mismatch('Deposit calldata is not a reviewed liquidity increase');\n }\n}\n\nexport function reviewV3CollectCalldata(data: Hex, recipient: Address, tokenId: bigint): void {\n try {\n const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });\n if (decoded.functionName !== 'collect') mismatch('Uniswap fee-claim transaction calldata is not a reviewed collect call');\n if (decoded.args[0].tokenId !== tokenId) mismatch('Uniswap fee-claim transaction targets a different position NFT');\n if (!same(decoded.args[0].recipient, recipient)) mismatch('Uniswap fee-claim transaction collects to a different recipient');\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n mismatch('Fee-claim calldata is not a reviewed collect call');\n }\n}\n\nexport function reviewV3CompoundCalldata(data: Hex, recipient: Address, tokenId: bigint): void {\n try {\n const decoded = decodeFunctionData({ abi: v3PositionManagerAbi, data });\n if (decoded.functionName !== 'multicall' || decoded.args[0].length !== 2) mismatch('Compound calldata must contain exactly collect and increase calls');\n reviewV3CollectCalldata(decoded.args[0][0], recipient, tokenId);\n reviewV3IncreaseLiquidityCalldata(decoded.args[0][1], tokenId);\n } catch (error) {\n if (error instanceof UniswapSdkError) throw error;\n mismatch('Compound calldata is not a reviewed position-manager multicall');\n }\n}\n"]}
|
package/dist/v3.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { multicall3Abi, V3_MAX_UINT128, v3Erc20Abi, v3FactoryAbi, v3PoolAbi, v3PositionManagerAbi, v3PositionManagerEventAbi, } from './v3-abis.js';
|
|
2
|
+
export * from './v3-transactions.js';
|
|
3
|
+
export * from './v3-receipts.js';
|
|
4
|
+
export * from './deployments.js';
|
|
5
|
+
export * from './compatibility.js';
|
|
6
|
+
//# sourceMappingURL=v3.d.ts.map
|
package/dist/v3.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3.d.ts","sourceRoot":"","sources":["../src/v3.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC"}
|
package/dist/v3.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { multicall3Abi, V3_MAX_UINT128, v3Erc20Abi, v3FactoryAbi, v3PoolAbi, v3PositionManagerAbi, v3PositionManagerEventAbi, } from './v3-abis.js';
|
|
2
|
+
export * from './v3-transactions.js';
|
|
3
|
+
export * from './v3-receipts.js';
|
|
4
|
+
export * from './deployments.js';
|
|
5
|
+
export * from './compatibility.js';
|
|
6
|
+
//# sourceMappingURL=v3.js.map
|
package/dist/v3.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v3.js","sourceRoot":"","sources":["../src/v3.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,oBAAoB,CAAC","sourcesContent":["export {\n multicall3Abi,\n V3_MAX_UINT128,\n v3Erc20Abi,\n v3FactoryAbi,\n v3PoolAbi,\n v3PositionManagerAbi,\n v3PositionManagerEventAbi,\n} from './v3-abis.js';\nexport * from './v3-transactions.js';\nexport * from './v3-receipts.js';\nexport * from './deployments.js';\nexport * from './compatibility.js';\n"]}
|
package/dist/v4.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { poolKeyFromCurrencies, getV4PoolId, poolReference } from './pool.js';
|
|
2
|
+
export type { V4Deployment, V4PoolKey, V4PoolReference } from './pool.js';
|
|
3
|
+
export { readV4Pool, quoteV4ExactInput, quoteV4Batch, verifyV4DeploymentWiring } from './reads.js';
|
|
4
|
+
export type { V4ReadClient, V4Observation, V4PoolSnapshot, V4QuoteInput, V4Quote, V4QuoteResult } from './reads.js';
|
|
5
|
+
export { readV4TickWindow, ticksInWord } from './depth.js';
|
|
6
|
+
export type { V4Tick, V4TickWindow } from './depth.js';
|
|
7
|
+
export { decodeV4PoolInitialization } from './events.js';
|
|
8
|
+
//# sourceMappingURL=v4.d.ts.map
|
package/dist/v4.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v4.d.ts","sourceRoot":"","sources":["../src/v4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC9E,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AACnG,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACpH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3D,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/v4.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { poolKeyFromCurrencies, getV4PoolId, poolReference } from './pool.js';
|
|
2
|
+
export { readV4Pool, quoteV4ExactInput, quoteV4Batch, verifyV4DeploymentWiring } from './reads.js';
|
|
3
|
+
export { readV4TickWindow, ticksInWord } from './depth.js';
|
|
4
|
+
export { decodeV4PoolInitialization } from './events.js';
|
|
5
|
+
//# sourceMappingURL=v4.js.map
|
package/dist/v4.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v4.js","sourceRoot":"","sources":["../src/v4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE9E,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAEnG,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC","sourcesContent":["export { poolKeyFromCurrencies, getV4PoolId, poolReference } from './pool.js';\nexport type { V4Deployment, V4PoolKey, V4PoolReference } from './pool.js';\nexport { readV4Pool, quoteV4ExactInput, quoteV4Batch, verifyV4DeploymentWiring } from './reads.js';\nexport type { V4ReadClient, V4Observation, V4PoolSnapshot, V4QuoteInput, V4Quote, V4QuoteResult } from './reads.js';\nexport { readV4TickWindow, ticksInWord } from './depth.js';\nexport type { V4Tick, V4TickWindow } from './depth.js';\nexport { decodeV4PoolInitialization } from './events.js';\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Uniswap v3 fork testing
|
|
2
|
+
|
|
3
|
+
The fork suite pins Robinhood mainnet block `60269962` with hash
|
|
4
|
+
`0x0c8248fedd0d28673c6852b5d65d806dfad9be361e4d90ed5a84664ca72fd8bf`.
|
|
5
|
+
It checks deployment runtime hashes and position-manager wiring, then uses an
|
|
6
|
+
impersonated owner of position `1132071` to execute an SDK-built full close.
|
|
7
|
+
The suite reviews the exact calldata before submission, simulates the complete
|
|
8
|
+
close to quote the principal and collected token amounts, then verifies that
|
|
9
|
+
the executed receipt contains those exact collection amounts alongside the
|
|
10
|
+
liquidity removal and NFT burn. It also confirms the final absence of `ownerOf`.
|
|
11
|
+
|
|
12
|
+
Install Foundry so `anvil` is available, provide an archive-capable Robinhood
|
|
13
|
+
mainnet endpoint, and run:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
SDK_FORK_EIP155_4663_RPC_URL=https://example.invalid npm run test:fork
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The public Robinhood RPC served the pinned fork during this review, but its
|
|
20
|
+
long-term historical retention is not contractual. Use an archive-capable RPC
|
|
21
|
+
if that endpoint stops serving block `60269962`. The test skips when the
|
|
22
|
+
chain-scoped variable is unset and fails closed if the
|
|
23
|
+
block hash, deployment code, wiring, position owner, or liquidity has changed.
|
|
24
|
+
No private key is used and all state changes remain inside Anvil.
|