price() fixes; sepolia redeploy

This commit is contained in:
tim
2025-11-25 23:11:38 -04:00
parent 2efcd4c0d3
commit cce229b99c
29 changed files with 140 additions and 57 deletions

View File

@@ -82,7 +82,7 @@ DIVE=$(token DIVE)
BUTC=$(token BUTC)
WTETH=$(token WTETH)
if [ "$1" == "broadcast" ]; then
if [ "$1" == "broadcast" ] || [ "$1" == "record" ]; then
OUT=deployment/$CHAINID/v1
git rm -rf $OUT > /dev/null 2>&1
mkdir -p $OUT

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea264697066735822122043a81c5a8112d10309d1ad8e6f619479e20ed7226ff1858199395f0823c2442864736f6c634300081e0033","sourceMap":"552:41558:43:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea264697066735822122043a81c5a8112d10309d1ad8e6f619479e20ed7226ff1858199395f0823c2442864736f6c634300081e0033","sourceMap":"552:41558:43:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Stabilized LMSR library with incremental exp(z) caching for gas efficiency. - Stores b (64.64), M (shift), Z = sum exp(z_i), z[i] = (q_i / b) - M - Caches e[i] = exp(z[i]) so we avoid recomputing exp() for every asset on each trade. - Provides closed-form \\u0394C on deposit, amount-out for asset->asset, and incremental applyDeposit/applyWithdraw that update e[i] and Z in O(1).\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/LMSRStabilized.sol\":\"LMSRStabilized\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":100000000},\"remappings\":[\":@abdk/=lib/abdk-libraries-solidity/\",\":@openzeppelin/=lib/openzeppelin-contracts/\",\":abdk-libraries-solidity/=lib/abdk-libraries-solidity/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\"],\"viaIR\":true},\"sources\":{\"lib/abdk-libraries-solidity/ABDKMath64x64.sol\":{\"keccak256\":\"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97\",\"license\":\"BSD-4-Clause\",\"urls\":[\"bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7\",\"dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN\"]},\"src/LMSRStabilized.sol\":{\"keccak256\":\"0x0a242f1378f609f0af4a2d9686287b33a7279fb987df0db43705f417b46ab68b\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://b9f834fcccf2e080fb5578afbe34dc3d8ac02b3f3364e0c2224bf30dcb32c1f3\",\"dweb:/ipfs/QmdN7rT5AnGNTyiHC22mYpxkk6T7cmjEkFgtcJvGM3roLB\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@abdk/=lib/abdk-libraries-solidity/","@openzeppelin/=lib/openzeppelin-contracts/","abdk-libraries-solidity/=lib/abdk-libraries-solidity/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"optimizer":{"enabled":true,"runs":100000000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/LMSRStabilized.sol":"LMSRStabilized"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/abdk-libraries-solidity/ABDKMath64x64.sol":{"keccak256":"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97","urls":["bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7","dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN"],"license":"BSD-4-Clause"},"src/LMSRStabilized.sol":{"keccak256":"0x0a242f1378f609f0af4a2d9686287b33a7279fb987df0db43705f417b46ab68b","urls":["bzz-raw://b9f834fcccf2e080fb5578afbe34dc3d8ac02b3f3364e0c2224bf30dcb32c1f3","dweb:/ipfs/QmdN7rT5AnGNTyiHC22mYpxkk6T7cmjEkFgtcJvGM3roLB"],"license":"UNLICENSED"}},"version":1},"id":43}
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220288026f9bad8209383b7c65335141f189d46488ae0e6c099c478c30b4d4815cc64736f6c634300081e0033","sourceMap":"257:41609:43:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220288026f9bad8209383b7c65335141f189d46488ae0e6c099c478c30b4d4815cc64736f6c634300081e0033","sourceMap":"257:41609:43:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Numerically stable library for a Logarithmic Market Scoring Rule based AMM. See docs/whitepaper.md\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/LMSRStabilized.sol\":\"LMSRStabilized\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":100000000},\"remappings\":[\":@abdk/=lib/abdk-libraries-solidity/\",\":@openzeppelin/=lib/openzeppelin-contracts/\",\":abdk-libraries-solidity/=lib/abdk-libraries-solidity/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\"],\"viaIR\":true},\"sources\":{\"lib/abdk-libraries-solidity/ABDKMath64x64.sol\":{\"keccak256\":\"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97\",\"license\":\"BSD-4-Clause\",\"urls\":[\"bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7\",\"dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN\"]},\"src/LMSRStabilized.sol\":{\"keccak256\":\"0x3add67dcba0369bfc622f3b5ffcb4ae659d9570d87244890d3a02cdf2c352531\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://e01dad20fe011d602804411e11d9c0659bbe5e9c749b2c025e7a9bf9b97004e9\",\"dweb:/ipfs/Qme1ataY1d7GVjgBzgd2ftqZzQ5yZ7n8B3JGJsmRfSfhTK\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@abdk/=lib/abdk-libraries-solidity/","@openzeppelin/=lib/openzeppelin-contracts/","abdk-libraries-solidity/=lib/abdk-libraries-solidity/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"optimizer":{"enabled":true,"runs":100000000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/LMSRStabilized.sol":"LMSRStabilized"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/abdk-libraries-solidity/ABDKMath64x64.sol":{"keccak256":"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97","urls":["bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7","dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN"],"license":"BSD-4-Clause"},"src/LMSRStabilized.sol":{"keccak256":"0x3add67dcba0369bfc622f3b5ffcb4ae659d9570d87244890d3a02cdf2c352531","urls":["bzz-raw://e01dad20fe011d602804411e11d9c0659bbe5e9c749b2c025e7a9bf9b97004e9","dweb:/ipfs/Qme1ataY1d7GVjgBzgd2ftqZzQ5yZ7n8B3JGJsmRfSfhTK"],"license":"UNLICENSED"}},"version":1},"id":43}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea26469706673582212207b738d2a73692c4ef9caa0271e6969b1039466e2d67d251b700fd148ddd9dc3e64736f6c634300081e0033","sourceMap":"265:8588:44:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea26469706673582212207b738d2a73692c4ef9caa0271e6969b1039466e2d67d251b700fd148ddd9dc3e64736f6c634300081e0033","sourceMap":"265:8588:44:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Specialized functions for the 2-asset stablecoin case\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/LMSRStabilizedBalancedPair.sol\":\"LMSRStabilizedBalancedPair\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":100000000},\"remappings\":[\":@abdk/=lib/abdk-libraries-solidity/\",\":@openzeppelin/=lib/openzeppelin-contracts/\",\":abdk-libraries-solidity/=lib/abdk-libraries-solidity/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\"],\"viaIR\":true},\"sources\":{\"lib/abdk-libraries-solidity/ABDKMath64x64.sol\":{\"keccak256\":\"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97\",\"license\":\"BSD-4-Clause\",\"urls\":[\"bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7\",\"dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN\"]},\"src/LMSRStabilized.sol\":{\"keccak256\":\"0x0a242f1378f609f0af4a2d9686287b33a7279fb987df0db43705f417b46ab68b\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://b9f834fcccf2e080fb5578afbe34dc3d8ac02b3f3364e0c2224bf30dcb32c1f3\",\"dweb:/ipfs/QmdN7rT5AnGNTyiHC22mYpxkk6T7cmjEkFgtcJvGM3roLB\"]},\"src/LMSRStabilizedBalancedPair.sol\":{\"keccak256\":\"0x782f3baf92f74152c0b93b95199abbb3a36c75c921454260c8b0237f91d7c59d\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://04d463c4fdcb6c8e2ebf9aed649ff21cca759ba73a4c93659e30c7df25e26c81\",\"dweb:/ipfs/QmUxmWytiw5VYJRUrFbSGm1oWmDPQ4q23pnkmK1q9P4apN\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@abdk/=lib/abdk-libraries-solidity/","@openzeppelin/=lib/openzeppelin-contracts/","abdk-libraries-solidity/=lib/abdk-libraries-solidity/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"optimizer":{"enabled":true,"runs":100000000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/LMSRStabilizedBalancedPair.sol":"LMSRStabilizedBalancedPair"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/abdk-libraries-solidity/ABDKMath64x64.sol":{"keccak256":"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97","urls":["bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7","dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN"],"license":"BSD-4-Clause"},"src/LMSRStabilized.sol":{"keccak256":"0x0a242f1378f609f0af4a2d9686287b33a7279fb987df0db43705f417b46ab68b","urls":["bzz-raw://b9f834fcccf2e080fb5578afbe34dc3d8ac02b3f3364e0c2224bf30dcb32c1f3","dweb:/ipfs/QmdN7rT5AnGNTyiHC22mYpxkk6T7cmjEkFgtcJvGM3roLB"],"license":"UNLICENSED"},"src/LMSRStabilizedBalancedPair.sol":{"keccak256":"0x782f3baf92f74152c0b93b95199abbb3a36c75c921454260c8b0237f91d7c59d","urls":["bzz-raw://04d463c4fdcb6c8e2ebf9aed649ff21cca759ba73a4c93659e30c7df25e26c81","dweb:/ipfs/QmUxmWytiw5VYJRUrFbSGm1oWmDPQ4q23pnkmK1q9P4apN"],"license":"UNLICENSED"}},"version":1},"id":44}
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea264697066735822122097909cdc0331ed3fb8e0cb19d8cabe91bee9ca2bd1200cfaaf1e50442b1470d564736f6c634300081e0033","sourceMap":"265:8588:44:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea264697066735822122097909cdc0331ed3fb8e0cb19d8cabe91bee9ca2bd1200cfaaf1e50442b1470d564736f6c634300081e0033","sourceMap":"265:8588:44:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"Specialized functions for the 2-asset stablecoin case\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/LMSRStabilizedBalancedPair.sol\":\"LMSRStabilizedBalancedPair\"},\"evmVersion\":\"prague\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":100000000},\"remappings\":[\":@abdk/=lib/abdk-libraries-solidity/\",\":@openzeppelin/=lib/openzeppelin-contracts/\",\":abdk-libraries-solidity/=lib/abdk-libraries-solidity/\",\":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/\",\":forge-std/=lib/forge-std/src/\",\":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/\",\":openzeppelin-contracts/=lib/openzeppelin-contracts/\"],\"viaIR\":true},\"sources\":{\"lib/abdk-libraries-solidity/ABDKMath64x64.sol\":{\"keccak256\":\"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97\",\"license\":\"BSD-4-Clause\",\"urls\":[\"bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7\",\"dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN\"]},\"src/LMSRStabilized.sol\":{\"keccak256\":\"0x3add67dcba0369bfc622f3b5ffcb4ae659d9570d87244890d3a02cdf2c352531\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://e01dad20fe011d602804411e11d9c0659bbe5e9c749b2c025e7a9bf9b97004e9\",\"dweb:/ipfs/Qme1ataY1d7GVjgBzgd2ftqZzQ5yZ7n8B3JGJsmRfSfhTK\"]},\"src/LMSRStabilizedBalancedPair.sol\":{\"keccak256\":\"0x782f3baf92f74152c0b93b95199abbb3a36c75c921454260c8b0237f91d7c59d\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://04d463c4fdcb6c8e2ebf9aed649ff21cca759ba73a4c93659e30c7df25e26c81\",\"dweb:/ipfs/QmUxmWytiw5VYJRUrFbSGm1oWmDPQ4q23pnkmK1q9P4apN\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["@abdk/=lib/abdk-libraries-solidity/","@openzeppelin/=lib/openzeppelin-contracts/","abdk-libraries-solidity/=lib/abdk-libraries-solidity/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"optimizer":{"enabled":true,"runs":100000000},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/LMSRStabilizedBalancedPair.sol":"LMSRStabilizedBalancedPair"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/abdk-libraries-solidity/ABDKMath64x64.sol":{"keccak256":"0x1364fdc24192b982f647c7fc68dcb2f6fc1b5e201843e773144bd23a76cb3b97","urls":["bzz-raw://490712cc07db32f274899b17aade9c975f06010848c21500b8a5ead6898e09c7","dweb:/ipfs/QmZMPKjDgwCFSGdLWJW6g5E7hDLByA9hNjXzAwJ4GKTZvN"],"license":"BSD-4-Clause"},"src/LMSRStabilized.sol":{"keccak256":"0x3add67dcba0369bfc622f3b5ffcb4ae659d9570d87244890d3a02cdf2c352531","urls":["bzz-raw://e01dad20fe011d602804411e11d9c0659bbe5e9c749b2c025e7a9bf9b97004e9","dweb:/ipfs/Qme1ataY1d7GVjgBzgd2ftqZzQ5yZ7n8B3JGJsmRfSfhTK"],"license":"UNLICENSED"},"src/LMSRStabilizedBalancedPair.sol":{"keccak256":"0x782f3baf92f74152c0b93b95199abbb3a36c75c921454260c8b0237f91d7c59d","urls":["bzz-raw://04d463c4fdcb6c8e2ebf9aed649ff21cca759ba73a4c93659e30c7df25e26c81","dweb:/ipfs/QmUxmWytiw5VYJRUrFbSGm1oWmDPQ4q23pnkmK1q9P4apN"],"license":"UNLICENSED"}},"version":1},"id":44}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"id":"1bebe326558dd054","source_id_to_path":{"0":"lib/abdk-libraries-solidity/ABDKMath64x64.sol","1":"lib/forge-std/src/Base.sol","2":"lib/forge-std/src/Script.sol","3":"lib/forge-std/src/StdChains.sol","4":"lib/forge-std/src/StdCheats.sol","5":"lib/forge-std/src/StdConstants.sol","6":"lib/forge-std/src/StdJson.sol","7":"lib/forge-std/src/StdMath.sol","8":"lib/forge-std/src/StdStorage.sol","9":"lib/forge-std/src/StdStyle.sol","10":"lib/forge-std/src/StdUtils.sol","11":"lib/forge-std/src/Vm.sol","12":"lib/forge-std/src/console.sol","13":"lib/forge-std/src/console2.sol","14":"lib/forge-std/src/interfaces/IMulticall3.sol","15":"lib/forge-std/src/safeconsole.sol","16":"lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol","17":"lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol","18":"lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol","19":"lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol","20":"lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol","21":"lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol","22":"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol","23":"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol","24":"lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol","25":"lib/openzeppelin-contracts/contracts/utils/Address.sol","26":"lib/openzeppelin-contracts/contracts/utils/Context.sol","27":"lib/openzeppelin-contracts/contracts/utils/Errors.sol","28":"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol","29":"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol","30":"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol","31":"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol","32":"script/DeploySepolia.sol","33":"src/ERC20External.sol","34":"src/ERC20Internal.sol","35":"src/Funding.sol","36":"src/IOwnable.sol","37":"src/IPartyFlashCallback.sol","38":"src/IPartyInfo.sol","39":"src/IPartyPlanner.sol","40":"src/IPartyPool.sol","41":"src/IPartyPoolDeployer.sol","42":"src/IPartySwapCallback.sol","43":"src/LMSRStabilized.sol","44":"src/LMSRStabilizedBalancedPair.sol","45":"src/NativeWrapper.sol","46":"src/OwnableExternal.sol","47":"src/OwnableInternal.sol","48":"src/PartyInfo.sol","49":"src/PartyPlanner.sol","50":"src/PartyPool.sol","51":"src/PartyPoolBalancedPair.sol","52":"src/PartyPoolBase.sol","53":"src/PartyPoolDeployer.sol","54":"src/PartyPoolHelpers.sol","55":"src/PartyPoolMintImpl.sol","56":"src/PartyPoolSwapImpl.sol","57":"src/PartyPoolVerifiableDeployer.sol","58":"src/PartySwapCallbackVerifier.sol","59":"test/MockERC20.sol","60":"test/MockFlashBorrower.sol"},"language":"Solidity"}
{"id":"7b2e43cf2890dc03","source_id_to_path":{"0":"lib/abdk-libraries-solidity/ABDKMath64x64.sol","1":"lib/forge-std/src/Base.sol","2":"lib/forge-std/src/Script.sol","3":"lib/forge-std/src/StdChains.sol","4":"lib/forge-std/src/StdCheats.sol","5":"lib/forge-std/src/StdConstants.sol","6":"lib/forge-std/src/StdJson.sol","7":"lib/forge-std/src/StdMath.sol","8":"lib/forge-std/src/StdStorage.sol","9":"lib/forge-std/src/StdStyle.sol","10":"lib/forge-std/src/StdUtils.sol","11":"lib/forge-std/src/Vm.sol","12":"lib/forge-std/src/console.sol","13":"lib/forge-std/src/console2.sol","14":"lib/forge-std/src/interfaces/IMulticall3.sol","15":"lib/forge-std/src/safeconsole.sol","16":"lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol","17":"lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol","18":"lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol","19":"lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol","20":"lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol","21":"lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol","22":"lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol","23":"lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol","24":"lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol","25":"lib/openzeppelin-contracts/contracts/utils/Address.sol","26":"lib/openzeppelin-contracts/contracts/utils/Context.sol","27":"lib/openzeppelin-contracts/contracts/utils/Errors.sol","28":"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol","29":"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol","30":"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol","31":"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol","32":"script/DeploySepolia.sol","33":"src/ERC20External.sol","34":"src/ERC20Internal.sol","35":"src/Funding.sol","36":"src/IOwnable.sol","37":"src/IPartyFlashCallback.sol","38":"src/IPartyInfo.sol","39":"src/IPartyPlanner.sol","40":"src/IPartyPool.sol","41":"src/IPartyPoolDeployer.sol","42":"src/IPartySwapCallback.sol","43":"src/LMSRStabilized.sol","44":"src/LMSRStabilizedBalancedPair.sol","45":"src/NativeWrapper.sol","46":"src/OwnableExternal.sol","47":"src/OwnableInternal.sol","48":"src/PartyInfo.sol","49":"src/PartyPlanner.sol","50":"src/PartyPool.sol","51":"src/PartyPoolBalancedPair.sol","52":"src/PartyPoolBase.sol","53":"src/PartyPoolDeployer.sol","54":"src/PartyPoolHelpers.sol","55":"src/PartyPoolMintImpl.sol","56":"src/PartyPoolSwapImpl.sol","57":"src/PartyPoolVerifiableDeployer.sol","58":"src/PartySwapCallbackVerifier.sol","59":"test/MockERC20.sol","60":"test/MockFlashBorrower.sol"},"language":"Solidity"}

View File

@@ -11,10 +11,10 @@
},
"11155111": {
"v1": {
"PartyPlanner": "0x1071097336Fd33298975efeC9C0bbc0bfB669da6",
"PartyInfo": "0x72582cD75AE8CF2934dc2909565A5858d30Eb2F8",
"PartyPoolMintImpl": "0xE40D300B7Dfff73b457BBB5A0d42dd4D88Ae9dD1",
"PartyPoolSwapImpl": "0x1b60fa6a7625477EC04B5FaA857e5022Ab1DF6E9",
"PartyPlanner": "0x025819444cE9fF0D0ACb729f1a8fF4449b7B1C8A",
"PartyInfo": "0x8f98B899F4135408Fe03228cE942Ad6BF8E40f22",
"PartyPoolMintImpl": "0xB424B96B40b0E7918e5e8f3fE4406Db6Ca49e303",
"PartyPoolSwapImpl": "0xdfcBcB7C84f4581F3e117C941eE46799f172C68c",
"PartyPoolInitCode": "",
"PartyPoolBalancedPairInitCode": "",
"USXD": "0x8E4D16886b8946dfE463fA172129eaBf4825fb09",

View File

@@ -4,15 +4,15 @@
We present a multi-asset automated market maker whose pricing kernel is the Logarithmic Market Scoring Rule (LMSR) ([R. Hanson, 2002](https://mason.gmu.edu/~rhanson/mktscore.pdf)). The pool maintains the convex potential $C(\mathbf{q}) = b(\mathbf{q}) \log\!\Big(\sum_i e^{q_i / b(\mathbf{q})}\Big)$ over normalized inventories $\mathbf{q}$, and sets the effective liquidity parameter proportional to pool size as $b(\mathbf{q}) = \kappa \, S(\mathbf{q})$ with $S(\mathbf{q}) = \sum_i q_i$ and fixed $\kappa>0$. This proportional parameterization preserves scale-invariant responsiveness while retaining softmax-derived pairwise price ratios under a quasi-static-$b$ view, enabling any-to-any swaps within a single potential. We derive and use closed-form expressions for two-asset reductions to compute exact-in, exact-out, limit-hitting (swap-to-limit), and capped-output trades. We discuss stability techniques such as log-sum-exp, ratio-once shortcuts, and domain guards for fixed-point arithmetic. Liquidity operations (proportional and single-asset joins/exits) follow directly from the same potential and admit monotone, invertible mappings. Parameters are immutable post-deployment for transparency and predictable depth calibration.
## Introduction and Motivation
Multi-asset liquidity typically trades off simplicity and expressivity. Classical CFMMs define multiplicative invariants over reserves, while LMSR specifies a convex cost function whose gradient yields prices. Our goal is a multi-asset AMM that uses LMSR to support any-to-any swaps, shares risk across many assets, and scales depth predictably with pool size. By setting $b(\mathbf{q})=\kappa S(\mathbf{q})$, we achieve scale invariance: proportional rescaling of all balances scales $b$ proportionally and preserves pairwise price ratios, so the markets responsiveness is consistent across liquidity regimes. The derivations below formulate instantaneous prices, closed-form swap mappings, limit logic, and liquidity operations tailored to this parameterization.
Classical CFMMs define multiplicative invariants over reserves, while LMSR specifies a convex cost function whose gradient yields prices. Our goal is a multi-asset AMM that uses LMSR to support any-to-any swaps, shares risk across many assets, and scales depth predictably with pool size. By setting $b(\mathbf{q})=\kappa S(\mathbf{q})$, we achieve scale invariance: proportional rescaling of all balances scales $b$ proportionally and preserves pairwise price ratios, so the markets responsiveness is consistent across liquidity regimes. The derivations below formulate instantaneous prices, closed-form swap mappings, limit logic, and liquidity operations tailored to this parameterization.
### Relation to liquidity-sensitive LMSR (Othman et al.)
[Othman et al., 2013](https://www.cs.cmu.edu/~sandholm/liquidity-sensitive%20market%20maker.EC10.pdf) introduce a liquidity-sensitive variant of LMSR (often called LS-LMSR) in which the liquidity parameter is allowed to evolve continuously via a scaling variable commonly denoted $\alpha$. Their formulation derives the full pricing equations for a continuously varying $b(\cdot)$ as $\alpha$ changes, and it purposefully ties the cost function to the path along which liquidity evolves.
- Conceptual correspondence: $\alpha$ in LS-LMSR plays a role analogous to our $\kappa$ in that both modulate how responsive prices are to inventory imbalances; in that sense $\alpha$ and $\kappa$ correspond as liquidity-scaling quantities. However, they are not identical: $\alpha$ in the LS-LMSR literature is a continuous scaling variable used to model an explicitly path-dependent evolution of $b$, while our $\kappa$ is a fixed proportionality constant and $b(\cdot)=\kappa\cdot S(\cdot)$ ties liquidity directly to the instantaneous pool size.
- Practical and formal differences: the continuous LS-LMSR pricing equations (with $\alpha$-driven evolution of $b$) generally give up path independence—the final cost can depend on the particular liquidity trajectory—whereas our design preserves path independence on a piecewise or quasi-static basis by evaluating swap steps with $b$ held at the local pre-trade state and then updating $b$ according to the new $S$. This yields a pool that is easier to reason about and whose swap mappings admit closed-form two-asset reductions.
- EVM feasibility: the exact continuous LS-LMSR price rules require richer integrals and state-continuous formulas that are substantially more gas-intensive to evaluate on-chain. For that reason we adopt a piecewise/quasi-static treatment that recovers softmax-driven pairwise ratios within each operation and updates $b$ discretely with state changes—combining tractable closed forms, numerical safety, and gas-efficiency.
- Naming and convention: because our approach keeps the liquidity sensitivity but enforces quasi-static (piecewise) evaluation, we call it "quasi-static LS-LMSR" rather than LS-LMSR. In the remainder of this document, we use $\kappa$ to denote our fixed proportionality; $\kappa$ corresponds to, but is not the same object as, the $\alpha$ used when deriving continuous LS-LMSR.
- Takeaway: Othman et al.'s treatment is closely related in spirit and provides valuable theoretical context, but the continuous $\alpha$-driven pricing equations differ formally from the $\kappa\to b(\cdot)=\kappa S(\cdot)$ parameterization used here; our choice trades full path dependence for piecewise path independence and EVM practicality, while retaining liquidity sensitivity and predictable scaling.
[Othman et al., 2013](https://www.cs.cmu.edu/~sandholm/liquidity-sensitive%20market%20maker.EC10.pdf) introduce a liquidity-sensitive variant of LMSR called LS-LMSR in which the liquidity parameter is allowed to evolve continuously via a scaling variable commonly denoted $\alpha$. Their formulation derives the full pricing equations for a continuously varying $b(\cdot)$ as $\alpha$ changes, and it purposefully ties the cost function to the path along which liquidity evolves.
- **Conceptual correspondence:** $\alpha$ in LS-LMSR plays a role analogous to our $\kappa$ in that both modulate how responsive prices are to inventory imbalances; in that sense $\alpha$ and $\kappa$ correspond as liquidity-scaling quantities. However, they are not identical: $\alpha$ in the LS-LMSR literature is a continuous scaling variable used to model an explicitly path-dependent evolution of $b$, while our $\kappa$ is a fixed proportionality constant and $b(\cdot)=\kappa\cdot S(\cdot)$ ties liquidity directly to the instantaneous pool size.
- **Practical and formal differences:** the continuous LS-LMSR pricing equations (with $\alpha$-driven evolution of $b$) generally give up path independence—the final cost can depend on the particular liquidity trajectory—whereas our design preserves path independence on a piecewise or quasi-static basis by evaluating swap steps with $b$ held at the local pre-trade state and then updating $b$ according to the new $S$. This yields a pool that is easier to reason about and whose swap mappings admit closed-form two-asset reductions.
- **EVM feasibility:** the exact continuous LS-LMSR price rules require richer integrals and state-continuous formulas that are substantially more gas-intensive to evaluate on-chain. For that reason we adopt a piecewise/quasi-static treatment that recovers softmax-driven pairwise ratios within each operation and updates $b$ discretely with state changes—combining tractable closed forms, numerical safety, and gas-efficiency.
- **Naming and convention:** because our approach keeps the liquidity sensitivity but enforces quasi-static (piecewise) evaluation, we call it "quasi-static LS-LMSR" rather than LS-LMSR. In the remainder of this document, we use $\kappa$ to denote our fixed proportionality; $\kappa$ corresponds to, but is not the same object as, the $\alpha$ used when deriving continuous LS-LMSR.
- **Takeaway:** Othman et al.'s treatment is closely related in spirit and provides valuable theoretical context, but the continuous $\alpha$-driven pricing equations differ formally from the $\kappa\to b(\cdot)=\kappa S(\cdot)$ parameterization used here; our choice trades full path dependence for piecewise path independence and EVM practicality, while retaining liquidity sensitivity and predictable scaling.
## System Model and Pricing Kernel
We consider $n\ge 2$ normalized assets with state vector $\mathbf{q}=(q_0,\dots,q_{n-1})\in\mathbb{R}_{\ge 0}^{\,n}$ and size metric $S(\mathbf{q})=\sum_i q_i$. The kernel is the LMSR cost function

View File

@@ -751,18 +751,18 @@ library LMSRStabilized {
return e_i_acc.div(Z);
}
/// @notice Marginal price of `base` in terms of `quote` (p_quote / p_base) as Q64.64
/// @dev Returns exp((q_quote - q_base) / b). Indices must be valid and b > 0.
/// @notice Infinitesimal out-per-in marginal price for swap base->quote (p_base / p_quote) as Q64.64
/// @dev Returns exp((q_base - q_quote) / b). Indices must be valid and b > 0.
function price(State storage s, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal view returns (int128) {
return price(s.kappa, s.qInternal, baseTokenIndex, quoteTokenIndex);
}
/// @notice Pure version: Marginal price of `base` in terms of `quote` (p_quote / p_base) as Q64.64
/// @dev Returns exp((q_quote - q_base) / b). Indices must be valid and b > 0.
/// @notice Pure version: Infinitesimal out-per-in marginal price for swap base->quote (p_base / p_quote) as Q64.64
/// @dev Returns exp((q_base - q_quote) / b). Indices must be valid and b > 0.
/// @param kappa Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param baseTokenIndex Index of base token
/// @param quoteTokenIndex Index of quote token
/// @param baseTokenIndex Index of base (input) token
/// @param quoteTokenIndex Index of quote (output) token
/// @return Price in 64.64 fixed-point format
function price(int128 kappa, int128[] memory qInternal, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal pure returns (int128) {
int128 sizeMetric = _computeSizeMetric(qInternal);
@@ -772,9 +772,8 @@ library LMSRStabilized {
// Use reciprocal of b to avoid repeated divisions
int128 invB = ABDKMath64x64.div(ONE, b);
// Marginal price p_quote / p_base = exp((q_quote - q_base) / b)
return _exp(qInternal[quoteTokenIndex].sub(qInternal[baseTokenIndex]).mul(invB));
// Marginal price p_base / p_quote = exp((q_base - q_quote) / b)
return _exp(qInternal[baseTokenIndex].sub(qInternal[quoteTokenIndex]).mul(invB));
}
/// @notice Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64)

View File

@@ -1,7 +1,6 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import "forge-std/console2.sol";
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IPartyPool} from "./IPartyPool.sol";
@@ -36,30 +35,32 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
// Current marginal prices
//
/// @notice Marginal price of `base` denominated in `quote` as Q64.64.
/// @dev Returns the LMSR marginal price p_quote / p_base in ABDK 64.64 fixed-point format.
/// Useful for off-chain quoting; raw 64.64 value is returned (no scaling to token units).
/// @param baseTokenIndex index of the base asset (e.g., ETH)
/// @param quoteTokenIndex index of the quote asset (e.g., USD)
/// @return price Q64.64 value equal to quote per base (p_quote / p_base)
/// @notice Infinitesimal out-per-in marginal price for swap base->quote as Q64.64 (j per i).
/// @dev Returns p_base / p_quote in ABDK 64.64 format, scaled to external units by (denom_quote / denom_base).
/// This aligns with the swap kernel so that, fee-free, avg(out/in) ≤ price(base, quote) for exact-in trades.
/// @param baseTokenIndex index of the input (base) asset
/// @param quoteTokenIndex index of the output (quote) asset
/// @return price Q64.64 value equal to out-per-in (j per i), scaled to token units
function price(IPartyPool pool, uint256 baseTokenIndex, uint256 quoteTokenIndex) external view returns (int128) {
LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length;
require(nAssets > 0, "price: uninit");
require(baseTokenIndex < nAssets && quoteTokenIndex < nAssets, "price: idx");
// Directly get p_base / p_quote (i.e., p_i / p_j) internally
int128 internalPrice = LMSRStabilized.price(pool.kappa(), lmsr.qInternal, baseTokenIndex, quoteTokenIndex);
// Convert to external units
// Convert to external units: multiply by denom_quote / denom_base
uint256 bd = pool.denominators()[baseTokenIndex];
uint256 qd = pool.denominators()[quoteTokenIndex];
return internalPrice.mul(ABDKMath64x64.divu(qd, bd));
}
/// @notice Price of one LP token denominated in `quote` as Q64.64.
/// @dev Computes LMSR poolPrice (quote per unit internal qTotal) and scales it to LP units:
/// returns price_per_LP = poolPrice_quote * (totalSupply() / qTotal) in ABDK 64.64 format.
/// The returned value is raw Q64.64 and represents quote units per one LP token unit.
/// @notice Price of one LP token denominated in `quote` as Q64.64 (external quote units per LP).
/// @dev Let P_S^quote be the LMSR pool price "quote per unit of internal S = sum q_i" (Q64.64, internal quote units).
/// We convert to external quote per LP by:
/// price_per_LP = P_S^quote * (denom_quote) * (S_internal / totalSupply)
/// where denom_quote converts internal quote to external units, and S_internal/totalSupply maps per-S to per-LP.
/// @param quoteTokenIndex index of the quote asset in which to denominate the LP price
/// @return price Q64.64 value equal to quote per LP token unit
/// @return price Q64.64 value equal to external quote units per one LP token unit
function poolPrice(IPartyPool pool, uint256 quoteTokenIndex) external view returns (int128) {
LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length;

View File

@@ -1196,5 +1196,88 @@ contract PartyPoolTest is Test {
assertTrue(slippage <= tol, "price from info and swapAmounts should be close");
}
/// @notice Ensure sequence is monotonically non-increasing:
/// marginal (highest), then avg price for a de-minimis swap, then larger inputs.
function testPricesMonotoneDecreasingWithLargerInputs() public {
// Build tokens array
IERC20[] memory tokens = new IERC20[](3);
tokens[0] = IERC20(address(token0));
tokens[1] = IERC20(address(token1));
tokens[2] = IERC20(address(token2));
// Zero fees to avoid fee effects in avg price
uint256 feePpm = 0;
// Use moderate kappa to see price movement while avoiding numerical instability
int128 kappa = ABDKMath64x64.divu(1, 10);
// Use imbalanced deposits (3:1:1) so initial price is not 1.0 and price decay is observable
uint256[] memory deposits = new uint256[](3);
deposits[0] = INIT_BAL * 3;
deposits[1] = INIT_BAL;
deposits[2] = INIT_BAL;
// Fresh pool
(IPartyPool poolCustom, ) = Deploy.newPartyPoolWithDeposits(
"LP_MONO", "LP_MONO", tokens, kappa, feePpm, feePpm, false, deposits, 0
);
// Base = token1 (input), Quote = token0 (output)
uint256 base = 1;
uint256 quote = 0;
// Marginal out-per-in price (Q64.64)
int128 p0 = info.price(poolCustom, base, quote);
// Define de-minimis and larger inputs (in external units)
uint256 eps = INIT_BAL / 1000; // de-minimis relative to deposits
if (eps == 0) eps = 1;
uint256 a1 = eps * 5;
uint256 a2 = eps * 10;
uint256 a3 = eps * 50;
// Compute average prices p = amountOut / netIn (fee-free here; still compute netIn robustly)
int128 p_eps;
{
(uint256 grossIn, uint256 amountOut, uint256 inFee) = poolCustom.swapAmounts(base, quote, eps, 0);
uint256 netIn = grossIn > inFee ? grossIn - inFee : 0;
require(netIn > 0 && amountOut > 0, "nonzero quote");
p_eps = ABDKMath64x64.divu(amountOut, netIn);
}
int128 p_a1;
{
(uint256 grossIn, uint256 amountOut, uint256 inFee) = poolCustom.swapAmounts(base, quote, a1, 0);
uint256 netIn = grossIn > inFee ? grossIn - inFee : 0;
require(netIn > 0 && amountOut > 0, "nonzero quote");
p_a1 = ABDKMath64x64.divu(amountOut, netIn);
}
int128 p_a2;
{
(uint256 grossIn, uint256 amountOut, uint256 inFee) = poolCustom.swapAmounts(base, quote, a2, 0);
uint256 netIn = grossIn > inFee ? grossIn - inFee : 0;
require(netIn > 0 && amountOut > 0, "nonzero quote");
p_a2 = ABDKMath64x64.divu(amountOut, netIn);
}
int128 p_a3;
{
(uint256 grossIn, uint256 amountOut, uint256 inFee) = poolCustom.swapAmounts(base, quote, a3, 0);
uint256 netIn = grossIn > inFee ? grossIn - inFee : 0;
require(netIn > 0 && amountOut > 0, "nonzero quote");
p_a3 = ABDKMath64x64.divu(amountOut, netIn);
}
// Tolerance for fixed-point/rounding (~4e-5)
int128 tol = ABDKMath64x64.divu(4, 100_000);
// Assert monotone non-increasing: next <= prev + tol
assertTrue(p_eps <= p0.add(tol), "p(eps) must be <= marginal");
assertTrue(p_a1 <= p_eps.add(tol), "p(a1) must be <= p(eps)");
assertTrue(p_a2 <= p_a1.add(tol), "p(a2) must be <= p(a1)");
assertTrue(p_a3 <= p_a2.add(tol), "p(a3) must be <= p(a2)");
}
}
/* solhint-enable */