1 Commits

Author SHA1 Message Date
tim
96dc134769 fixed-b 2025-10-24 20:01:24 -04:00
94 changed files with 1213 additions and 1591 deletions

View File

@@ -1,3 +0,0 @@
Copyright ©2025 Dexorder LLC. All rights reserved.
No license is provided. This source code is viewable for verification purposes only.

View File

@@ -1,96 +0,0 @@
# Introduction
[Liquidity Party](https://liquidity.party) is a new game-theoretic multi-asset AMM based on this research paper:
[Logarithmic Market Scoring Rules for Modular Combinatorial Information Aggregation](https://mason.gmu.edu/~rhanson/mktscore.pdf) (R. Hanson, 2002)
Our formulation and implementation is described in the [Liquidity Party whitepaper.](doc/whitepaper.md)
A Logarithmic Market Scoring Rule (LMSR) is a pricing formula for AMM's that know only their current asset inventories
and no other information, naturally supporting multi-asset pools.
Compared to Constant Product markets, LMSR offers:
1. Less slippage than Constant Product for small and medium trade sizes
2. N-asset pools for trading long-tail pairs in a single hop
3. Lower fees (smaller spread)
## Deeper Liquidity
According to game theory, the initial price slope of a Constant Product AMM is too steep, overcharging takers
with too much slippage at small and medium trade sizes. LMSR pools offer less slippage and cheaper
liquidity for the small and medium trade sizes used by real traders.
## Multi-asset
Naturally multi-asset, Liquidity Party altcoin pools provide direct, one-hop swaps on otherwise illiquid multi-hop pairs. Pools will quote any pair combination available in the pool:
| Assets | Pairs | Swap Gas | Mint Gas |
|-------:|------:|---------:|----------:|
| 2 | 1 | 131,000 | 143,000 |
| 2* | 1 | 118,000 | 143,000 |
| 10 | 45 | 142,000 | 412,000 |
| 20 | 190 | 157,000 | 749,000 |
| 50 | 1225 | 199,000 | 1,760,000 |
| 100 | 4950 | 269,000 | 2,684,000 |
\* Stablecoin pair pool optimization
Liquidity Party aggregates scarce, low market cap assets into a single pool, providing one-hop liquidity for exotic pairs without fragmenting LP assets. CP pools would need 190x the LP assets to provide the same pairwise liquidity as a single 20-asset Liquidity Party pool, due to asset fragmentation.
## Lower Fees
Since market makers offer the option to take either side of the market, they must receive a subsidy or charge a fee (spread) to compensate for adverse selection (impermanent loss). By protecting LP's against common value-extraction scenarios, LMSR pools have a reduced risk premium resulting in lower fees for takers.
### Minimized Impermanent Loss
All AMM's suffer from Impermanent Loss (IL), also known as adverse selection or toxic order flow. Liquidity
Party uses game theory to minimize IL for LPs, by charging lower fees to small legitimate traders and
higher fees to large adversarial traders during market dislocations. This means a higher effective rate
for LP's and cheaper swaps for legitimate small traders.
Liquidity Party swaps guarantee a bounded maximum loss to LP's of `κ\*S\*ln(N)` where `κ` is
the pool's liquidity parameter, `S` is the total size of the pool, and `N` is the
number of assets in the pool.
### No Intra-Pool Arbitrage
Other multi-asset systems can provide inconsistent price quotes, allowing arbitragers to
extract value from LP's by _trading assets inside the same pool against each other._ With Liquidity
Party, no intra-pool arbitrage is possible, because the mathematics guarantee fully consistent price
quotes on all pairs in the pool.
# Installation
1. Install [Foundry](https://getfoundry.sh/) development framework.
2. Update dependencies with `forge install`
3. Run `bin/mock` to launch a test environment running under `anvil` on `localhost:8545`. The mock environment will create several example pools along with mock ERC20 tokens that can be minted by anyone in any amount.
# Integration
Deployment addresses for each chain may be found in `deployment/liqp-deployments.json`, and the `solc` output including ABI information is stored under `deployment/{chain_id}/v1/...`
The primary entrypoint for all Liquidity Party actions is the [PartyPlanner](src/IPartyPlanner.sol) contract, which is a singleton per chain. The `PartyPlanner` contract not only deploys new pools but also indexes the pools and their tokens for easy metadata discovery. After a pool is created or discovered using the `PartyPlanner`, it can be used to perform swaps, minting, and other actions according to the [IPartyPool](src/IPartyPlanner.sol) interface. Due to contract size limitations, most view methods for prices and swaps are available from a separate singleton contract, [PartyInfo](src/IPartyInfo.sol).
# Implementation Notes
## Non-upgradable Proxy
Due to contract size constraints, the `PartyPool` contract uses `DELEGATECALL` to invoke implementations on the singleton [PartyPoolSwapImpl](src/PartyPoolSwapImpl.sol) and [PartyPoolMintImpl](src/PartyPoolMintImpl.sol) contracts. This proxy pattern is NOT upgradable and the implementation contract addresses used by the pool are immutable. Views implemented in `PartyInfo` have no delegation but simply accept the target pool as an argument, calculating prices etc. from public getters.
## Admin-Only Deployment
`PartyPlanner` allows only the admin to deploy new pools. This decision was made because Liquidity Party is a new protocol that does not support non-standard tokens such as fee-on-transfer tokens or rebasing tokens, and the selection of the `kappa` liquidity parameter is not straightforward for an average user. We hope to offer a version of Liquidity Party in the future that allows regular users to create their pools.
## Killable Contracts
PartyPools may be "killed" by their admin, in which case all swaps and mints are disabled, and the only modifying function allowed to be called is `burn()` to allow LP's to safely withdraw their funds. Killing is irreversible and intended to be used as a last-ditch safety measure in case a critical vulnerablility is discovered.
## Fee Mechanisms
Each asset in the pool has a fee associated with it, which is paid when that asset is involved in a swap.
The fee for a swap is the input asset fee plus the output asset fee, but this total fee percentage is taken only from the input amount, prior to the LMSR calculation. This results in more of the input asset being collected by the pool compared to the value of the output asset removed. In this way, the LP holders accumulate fee value implicitly in their prorata share of the pool's total assets.
For a swap-mint operation, only the input asset fee is charged on the input token. For a burn-swap, only the output asset fee is charged on the output token.
Flash loans are charged a single fee, the flash fee, no matter what asset is loaned.
Protocol fees are taken as a fraction of any LP fees earned, rounding down in favor of the LP stakers. Protocol fees accumulate in a separate account in the pool until the admin sends a collection transaction to sweep the fees. While protocol fees are waiting to be collected, those funds do not participate in liquidity operations or earn fees.

View File

@@ -4,29 +4,25 @@
# Dev account #4 # Dev account #4
PRIVATE_KEY=0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a PRIVATE_KEY=0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
set -euo pipefail
# Function to cleanup processes # Function to cleanup processes
cleanup() { cleanup() {
if [[ -n "${ANVIL_PID:-}" ]] && kill -0 "$ANVIL_PID" 2>/dev/null; then kill $ANVIL_PID 2>/dev/null
kill "$ANVIL_PID" 2>/dev/null || true
sleep 0.2
kill -9 "$ANVIL_PID" 2>/dev/null || true
fi
} }
# Ensure cleanup on any exit err() {
cleanup
exit $1
}
# Set up trap to handle script exit
trap cleanup EXIT trap cleanup EXIT
# On Ctrl-C or TERM: exit immediately (will trigger EXIT trap -> cleanup)
trap 'exit 130' INT
trap 'exit 143' TERM
# Create log directory if it doesn't exist # Create log directory if it doesn't exist
mkdir -p log mkdir -p log
# Run anvil in background and redirect output to log file # Run anvil in background and redirect output to log file
# shellcheck disable=SC2086 # shellcheck disable=SC2086
anvil --disable-block-gas-limit | tee log/anvil.txt & anvil | tee log/anvil.txt &
ANVIL_PID=$! ANVIL_PID=$!
# Function to check if string exists in file # Function to check if string exists in file
@@ -47,13 +43,14 @@ while ! check_string "Listening on" "log/anvil.txt"; do
fi fi
done done
forge script --private-key ${PRIVATE_KEY} DeployMock --fork-url http://localhost:8545 --broadcast "$@" || exit 1 forge script --private-key ${PRIVATE_KEY} DeployMock --fork-url http://localhost:8545 --broadcast "$@" || err 1
if [ "${1:-}" = "slow" ]; then if [ "$1" = "slow" ]; then
echo "SLOW MODE: Setting mining mode to 12-second intervals." echo "SLOW MODE: Setting mining mode to 12-second intervals."
cast rpc evm_setIntervalMining 12 cast rpc evm_setIntervalMining 12
fi fi
echo "Press Ctrl+C to exit..." echo "Press Ctrl+C to exit..."
# Wait for the anvil process; Ctrl-C will interrupt 'wait' and trigger cleanup via traps while true; do
wait "$ANVIL_PID" sleep 1
done

View File

@@ -3,13 +3,6 @@
CHAINID=11155111 CHAINID=11155111
DEPLOY_SCRIPT=DeploySepolia DEPLOY_SCRIPT=DeploySepolia
if [ -f ".env-secret" ]; then
echo "Reading environment from .env-secret"
set -a
source .env-secret
set +a
fi
if [ -z "$SEPOLIA_RPC_URL" ]; then if [ -z "$SEPOLIA_RPC_URL" ]; then
echo "Usage: SEPOLIA_RPC_URL environment variable must be set" echo "Usage: SEPOLIA_RPC_URL environment variable must be set"
exit 1 exit 1
@@ -65,7 +58,7 @@ token() {
} }
PARTY_PLANNER=$(contract PartyPlanner) PARTY_PLANNER=$(contract PartyPlanner)
PARTY_INFO=$(contract PartyInfo) PARTY_POOL_VIEWER=$(contract PartyPoolViewer)
PARTY_POOL_MINT_IMPL=$(contract PartyPoolMintImpl) PARTY_POOL_MINT_IMPL=$(contract PartyPoolMintImpl)
PARTY_POOL_SWAP_IMPL=$(contract PartyPoolSwapImpl) PARTY_POOL_SWAP_IMPL=$(contract PartyPoolSwapImpl)
PARTY_POOL_DEPLOYER=$(contract PartyPoolDeployer) PARTY_POOL_DEPLOYER=$(contract PartyPoolDeployer)
@@ -85,7 +78,7 @@ cp -r out $OUT/
jq -n \ jq -n \
--arg chainId "$CHAINID" \ --arg chainId "$CHAINID" \
--arg partyPlanner "$PARTY_PLANNER" \ --arg partyPlanner "$PARTY_PLANNER" \
--arg partyInfo "$PARTY_INFO" \ --arg partyPoolViewer "$PARTY_POOL_VIEWER" \
--arg partyPoolMintImpl "$PARTY_POOL_MINT_IMPL" \ --arg partyPoolMintImpl "$PARTY_POOL_MINT_IMPL" \
--arg partyPoolSwapImpl "$PARTY_POOL_SWAP_IMPL" \ --arg partyPoolSwapImpl "$PARTY_POOL_SWAP_IMPL" \
--arg partyPoolDeployer "$PARTY_POOL_DEPLOYER" \ --arg partyPoolDeployer "$PARTY_POOL_DEPLOYER" \
@@ -99,7 +92,7 @@ jq -n \
{ {
v1: { v1: {
PartyPlanner: $partyPlanner, PartyPlanner: $partyPlanner,
PartyInfo: $partyInfo, PartyPoolViewer: $partyPoolViewer,
PartyPoolMintImpl: $partyPoolMintImpl, PartyPoolMintImpl: $partyPoolMintImpl,
PartyPoolSwapImpl: $partyPoolSwapImpl, PartyPoolSwapImpl: $partyPoolSwapImpl,
PartyPoolDeployer: $partyPoolDeployer, PartyPoolDeployer: $partyPoolDeployer,
@@ -116,7 +109,7 @@ jq -n \
jq -n \ jq -n \
--arg chainId "$CHAINID" \ --arg chainId "$CHAINID" \
--arg partyPlanner "$PARTY_PLANNER" \ --arg partyPlanner "$PARTY_PLANNER" \
--arg partyInfo "$PARTY_INFO" \ --arg partyPoolViewer "$PARTY_POOL_VIEWER" \
--arg partyPoolMintImpl "$PARTY_POOL_MINT_IMPL" \ --arg partyPoolMintImpl "$PARTY_POOL_MINT_IMPL" \
--arg partyPoolSwapImpl "$PARTY_POOL_SWAP_IMPL" \ --arg partyPoolSwapImpl "$PARTY_POOL_SWAP_IMPL" \
--arg partyPoolDeployer "$PARTY_POOL_DEPLOYER" \ --arg partyPoolDeployer "$PARTY_POOL_DEPLOYER" \
@@ -129,7 +122,7 @@ jq -n \
'{($chainId): { '{($chainId): {
v1: { v1: {
PartyPlanner: $partyPlanner, PartyPlanner: $partyPlanner,
PartyInfo.sol: $partyInfo, PartyPoolViewer: $partyPoolViewer,
PartyPoolMintImpl: $partyPoolMintImpl, PartyPoolMintImpl: $partyPoolMintImpl,
PartyPoolSwapImpl: $partyPoolSwapImpl, PartyPoolSwapImpl: $partyPoolSwapImpl,
PartyPoolDeployer: $partyPoolDeployer, PartyPoolDeployer: $partyPoolDeployer,

View File

@@ -1 +1 @@
{"abi":[{"type":"error","name":"AddressEmptyCode","inputs":[{"name":"target","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220eb0570070fec78251db3fa24b17454c9bec7df5e60c2499d03d66c5c28208ff764736f6c634300081e0033","sourceMap":"282:6520:27:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220eb0570070fec78251db3fa24b17454c9bec7df5e60c2499d03d66c5c28208ff764736f6c634300081e0033","sourceMap":"282:6520:27:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Address.sol\":\"Address\"},\"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/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0xd274645d15bb7e4fcb9c833e401b2c5837404f90057f11a49118f25e0af7c76f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d38e0b997bb7aebae26d190b03d0991feb0d204c45f945e60014e1ca9175de69\",\"dweb:/ipfs/QmWzsUHHAZcjMyF8uMDEtNpMTkYZdQrfvdKPobXvwVHKo6\"]},\"lib/openzeppelin-contracts/contracts/utils/Errors.sol\":{\"keccak256\":\"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf\",\"dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB\"]},\"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol\":{\"keccak256\":\"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848\",\"dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"type":"error","name":"AddressEmptyCode"}],"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":{"lib/openzeppelin-contracts/contracts/utils/Address.sol":"Address"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0xd274645d15bb7e4fcb9c833e401b2c5837404f90057f11a49118f25e0af7c76f","urls":["bzz-raw://d38e0b997bb7aebae26d190b03d0991feb0d204c45f945e60014e1ca9175de69","dweb:/ipfs/QmWzsUHHAZcjMyF8uMDEtNpMTkYZdQrfvdKPobXvwVHKo6"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/Errors.sol":{"keccak256":"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123","urls":["bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf","dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol":{"keccak256":"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5","urls":["bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848","dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4"],"license":"MIT"}},"version":1},"id":27} {"abi":[{"type":"error","name":"AddressEmptyCode","inputs":[{"name":"target","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220eb0570070fec78251db3fa24b17454c9bec7df5e60c2499d03d66c5c28208ff764736f6c634300081e0033","sourceMap":"282:6520:33:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220eb0570070fec78251db3fa24b17454c9bec7df5e60c2499d03d66c5c28208ff764736f6c634300081e0033","sourceMap":"282:6520:33:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"}],\"name\":\"AddressEmptyCode\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of functions related to the address type\",\"errors\":{\"AddressEmptyCode(address)\":[{\"details\":\"There's no code at `target` (it is not a contract).\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Address.sol\":\"Address\"},\"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/openzeppelin-contracts/contracts/utils/Address.sol\":{\"keccak256\":\"0xd274645d15bb7e4fcb9c833e401b2c5837404f90057f11a49118f25e0af7c76f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d38e0b997bb7aebae26d190b03d0991feb0d204c45f945e60014e1ca9175de69\",\"dweb:/ipfs/QmWzsUHHAZcjMyF8uMDEtNpMTkYZdQrfvdKPobXvwVHKo6\"]},\"lib/openzeppelin-contracts/contracts/utils/Errors.sol\":{\"keccak256\":\"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf\",\"dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB\"]},\"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol\":{\"keccak256\":\"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848\",\"dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"type":"error","name":"AddressEmptyCode"}],"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":{"lib/openzeppelin-contracts/contracts/utils/Address.sol":"Address"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Address.sol":{"keccak256":"0xd274645d15bb7e4fcb9c833e401b2c5837404f90057f11a49118f25e0af7c76f","urls":["bzz-raw://d38e0b997bb7aebae26d190b03d0991feb0d204c45f945e60014e1ca9175de69","dweb:/ipfs/QmWzsUHHAZcjMyF8uMDEtNpMTkYZdQrfvdKPobXvwVHKo6"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/Errors.sol":{"keccak256":"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123","urls":["bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf","dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol":{"keccak256":"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5","urls":["bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848","dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4"],"license":"MIT"}},"version":1},"id":33}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":\"Context\"},\"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/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]}},\"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":{"lib/openzeppelin-contracts/contracts/utils/Context.sol":"Context"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"keccak256":"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2","urls":["bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12","dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF"],"license":"MIT"}},"version":1},"id":28} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Provides information about the current execution context, including the sender of the transaction and its data. While these are generally available via msg.sender and msg.data, they should not be accessed in such a direct manner, since when dealing with meta-transactions the account sending and paying for execution may not be the actual sender (as far as an application is concerned). This contract is only required for intermediate, library-like contracts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Context.sol\":\"Context\"},\"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/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]}},\"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":{"lib/openzeppelin-contracts/contracts/utils/Context.sol":"Context"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"keccak256":"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2","urls":["bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12","dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF"],"license":"MIT"}},"version":1},"id":34}

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":[{"type":"error","name":"FailedCall","inputs":[]},{"type":"error","name":"FailedDeployment","inputs":[]},{"type":"error","name":"InsufficientBalance","inputs":[{"name":"balance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"MissingPrecompile","inputs":[{"name":"","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220c9655ed21113d5fdaf6c566485d35a2aaf2bf242b1c753a1cac998424bd77b5d64736f6c634300081e0033","sourceMap":"411:484:29:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220c9655ed21113d5fdaf6c566485d35a2aaf2bf242b1c753a1cac998424bd77b5d64736f6c634300081e0033","sourceMap":"411:484:29:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"FailedCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDeployment\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"MissingPrecompile\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of common custom errors used in multiple contracts IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. It is recommended to avoid relying on the error API for critical functionality. _Available since v5.1._\",\"errors\":{\"FailedCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"FailedDeployment()\":[{\"details\":\"The deployment failed.\"}],\"InsufficientBalance(uint256,uint256)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"MissingPrecompile(address)\":[{\"details\":\"A necessary precompile is missing.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Errors.sol\":\"Errors\"},\"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/openzeppelin-contracts/contracts/utils/Errors.sol\":{\"keccak256\":\"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf\",\"dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[],"type":"error","name":"FailedCall"},{"inputs":[],"type":"error","name":"FailedDeployment"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"type":"error","name":"InsufficientBalance"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"type":"error","name":"MissingPrecompile"}],"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":{"lib/openzeppelin-contracts/contracts/utils/Errors.sol":"Errors"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Errors.sol":{"keccak256":"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123","urls":["bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf","dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB"],"license":"MIT"}},"version":1},"id":29} {"abi":[{"type":"error","name":"FailedCall","inputs":[]},{"type":"error","name":"FailedDeployment","inputs":[]},{"type":"error","name":"InsufficientBalance","inputs":[{"name":"balance","type":"uint256","internalType":"uint256"},{"name":"needed","type":"uint256","internalType":"uint256"}]},{"type":"error","name":"MissingPrecompile","inputs":[{"name":"","type":"address","internalType":"address"}]}],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220c9655ed21113d5fdaf6c566485d35a2aaf2bf242b1c753a1cac998424bd77b5d64736f6c634300081e0033","sourceMap":"411:484:35:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220c9655ed21113d5fdaf6c566485d35a2aaf2bf242b1c753a1cac998424bd77b5d64736f6c634300081e0033","sourceMap":"411:484:35:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"FailedCall\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FailedDeployment\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"needed\",\"type\":\"uint256\"}],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"MissingPrecompile\",\"type\":\"error\"}],\"devdoc\":{\"details\":\"Collection of common custom errors used in multiple contracts IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. It is recommended to avoid relying on the error API for critical functionality. _Available since v5.1._\",\"errors\":{\"FailedCall()\":[{\"details\":\"A call to an address target failed. The target may have reverted.\"}],\"FailedDeployment()\":[{\"details\":\"The deployment failed.\"}],\"InsufficientBalance(uint256,uint256)\":[{\"details\":\"The ETH balance of the account is not enough to perform the operation.\"}],\"MissingPrecompile(address)\":[{\"details\":\"A necessary precompile is missing.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/Errors.sol\":\"Errors\"},\"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/openzeppelin-contracts/contracts/utils/Errors.sol\":{\"keccak256\":\"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf\",\"dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[],"type":"error","name":"FailedCall"},{"inputs":[],"type":"error","name":"FailedDeployment"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"type":"error","name":"InsufficientBalance"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"type":"error","name":"MissingPrecompile"}],"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":{"lib/openzeppelin-contracts/contracts/utils/Errors.sol":"Errors"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Errors.sol":{"keccak256":"0x6afa713bfd42cf0f7656efa91201007ac465e42049d7de1d50753a373648c123","urls":["bzz-raw://ba1d02f4847670a1b83dec9f7d37f0b0418d6043447b69f3a29a5f9efc547fcf","dweb:/ipfs/QmQ7iH2keLNUKgq2xSWcRmuBE5eZ3F5whYAkAGzCNNoEWB"],"license":"MIT"}},"version":1},"id":35}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"abi":[{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"supportsInterface(bytes4)":"01ffc9a7"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC-165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[ERC]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":\"IERC165\"},\"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/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617\",\"dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"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":{"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":"IERC165"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c","urls":["bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617","dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u"],"license":"MIT"}},"version":1},"id":33} {"abi":[{"type":"function","name":"supportsInterface","inputs":[{"name":"interfaceId","type":"bytes4","internalType":"bytes4"}],"outputs":[{"name":"","type":"bool","internalType":"bool"}],"stateMutability":"view"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"supportsInterface(bytes4)":"01ffc9a7"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"details\":\"Interface of the ERC-165 standard, as defined in the https://eips.ethereum.org/EIPS/eip-165[ERC]. Implementers can declare support of contract interfaces, which can then be queried by others ({ERC165Checker}). For an implementation, see {ERC165}.\",\"kind\":\"dev\",\"methods\":{\"supportsInterface(bytes4)\":{\"details\":\"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas.\"}},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":\"IERC165\"},\"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/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol\":{\"keccak256\":\"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617\",\"dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"stateMutability":"view","type":"function","name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"supportsInterface(bytes4)":{"details":"Returns true if this contract implements the interface defined by `interfaceId`. See the corresponding https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] to learn more about how these ids are created. This function call must use less than 30 000 gas."}},"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":{"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":"IERC165"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol":{"keccak256":"0x8891738ffe910f0cf2da09566928589bf5d63f4524dd734fd9cedbac3274dd5c","urls":["bzz-raw://971f954442df5c2ef5b5ebf1eb245d7105d9fbacc7386ee5c796df1d45b21617","dweb:/ipfs/QmadRjHbkicwqwwh61raUEapaVEtaLMcYbQZWs9gUkgj3u"],"license":"MIT"}},"version":1},"id":39}

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 @@
{"abi":[{"type":"function","name":"partyFlashCallback","inputs":[{"name":"loanAmounts","type":"uint256[]","internalType":"uint256[]"},{"name":"repaymentAmounts","type":"uint256[]","internalType":"uint256[]"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"partyFlashCallback(uint256[],uint256[],bytes)":"f6c10706"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"loanAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"repaymentAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"partyFlashCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/IPartyFlashCallback.sol\":\"IPartyFlashCallback\"},\"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\":{\"src/IPartyFlashCallback.sol\":{\"keccak256\":\"0xff1d473d27c4dc75441a5f0db2d761916cce4a702f660e998467791efd1d9b2e\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://3220d69c62ed8c8106762c92857f24011284e8ddcfa5db4210e506b112fa1870\",\"dweb:/ipfs/QmYoZiGsVwoJvyPMcsSste4tq93wVBgDqCZkwPY7dvyLBJ\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"uint256[]","name":"loanAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"repaymentAmounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"partyFlashCallback"}],"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/IPartyFlashCallback.sol":"IPartyFlashCallback"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"src/IPartyFlashCallback.sol":{"keccak256":"0xff1d473d27c4dc75441a5f0db2d761916cce4a702f660e998467791efd1d9b2e","urls":["bzz-raw://3220d69c62ed8c8106762c92857f24011284e8ddcfa5db4210e506b112fa1870","dweb:/ipfs/QmYoZiGsVwoJvyPMcsSste4tq93wVBgDqCZkwPY7dvyLBJ"],"license":"UNLICENSED"}},"version":1},"id":38} {"abi":[{"type":"function","name":"partyFlashCallback","inputs":[{"name":"loanAmounts","type":"uint256[]","internalType":"uint256[]"},{"name":"repaymentAmounts","type":"uint256[]","internalType":"uint256[]"},{"name":"data","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"partyFlashCallback(uint256[],uint256[],bytes)":"f6c10706"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"loanAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"repaymentAmounts\",\"type\":\"uint256[]\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"partyFlashCallback\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/IPartyFlashCallback.sol\":\"IPartyFlashCallback\"},\"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\":{\"src/IPartyFlashCallback.sol\":{\"keccak256\":\"0xff1d473d27c4dc75441a5f0db2d761916cce4a702f660e998467791efd1d9b2e\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://3220d69c62ed8c8106762c92857f24011284e8ddcfa5db4210e506b112fa1870\",\"dweb:/ipfs/QmYoZiGsVwoJvyPMcsSste4tq93wVBgDqCZkwPY7dvyLBJ\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"uint256[]","name":"loanAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"repaymentAmounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"nonpayable","type":"function","name":"partyFlashCallback"}],"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/IPartyFlashCallback.sol":"IPartyFlashCallback"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"src/IPartyFlashCallback.sol":{"keccak256":"0xff1d473d27c4dc75441a5f0db2d761916cce4a702f660e998467791efd1d9b2e","urls":["bzz-raw://3220d69c62ed8c8106762c92857f24011284e8ddcfa5db4210e506b112fa1870","dweb:/ipfs/QmYoZiGsVwoJvyPMcsSste4tq93wVBgDqCZkwPY7dvyLBJ"],"license":"UNLICENSED"}},"version":1},"id":45}

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":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220b3e7e7d176c75fd687d50408cdd3f2f0c44423e17a0f674e797ffbe7fae0105564736f6c634300081e0033","sourceMap":"552:41522:42:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220b3e7e7d176c75fd687d50408cdd3f2f0c44423e17a0f674e797ffbe7fae0105564736f6c634300081e0033","sourceMap":"552:41522:42:-: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\":\"0xb3df5a014bbb48a1aea62faee4ef9c7a830fcb0209cf1304bdca4fa68126a3f3\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://b05b0c09bb8883fed3c03509bf6f5f9991435ae6648530662b4fd01f667ab955\",\"dweb:/ipfs/QmeYVgnoXn3uiZdUsW2TYigfRPuHBR7AV1fpRm6uT9Z1gZ\"]}},\"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":"0xb3df5a014bbb48a1aea62faee4ef9c7a830fcb0209cf1304bdca4fa68126a3f3","urls":["bzz-raw://b05b0c09bb8883fed3c03509bf6f5f9991435ae6648530662b4fd01f667ab955","dweb:/ipfs/QmeYVgnoXn3uiZdUsW2TYigfRPuHBR7AV1fpRm6uT9Z1gZ"],"license":"UNLICENSED"}},"version":1},"id":42} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea264697066735822122066e35f3ae677f1cfa4ce90bb52d5d25b37cbc5fa99c2ecc24a1a4a8db5ae04a564736f6c634300081e0033","sourceMap":"552:43739:49:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea264697066735822122066e35f3ae677f1cfa4ce90bb52d5d25b37cbc5fa99c2ecc24a1a4a8db5ae04a564736f6c634300081e0033","sourceMap":"552:43739:49:-: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\":\"0xfbb5d611a105095a9ccc71f859908eec12ed7df4573a787e130bbaf9fbaa7935\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://4f37e539fdbedd38488f5c5f0c8a4f579693e8de1ca546b60c580d4d0e12b28b\",\"dweb:/ipfs/QmR6VvQs54XKH67DyWrWdLBf2n6XTYnTjRniY4CFihZAVN\"]}},\"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":"0xfbb5d611a105095a9ccc71f859908eec12ed7df4573a787e130bbaf9fbaa7935","urls":["bzz-raw://4f37e539fdbedd38488f5c5f0c8a4f579693e8de1ca546b60c580d4d0e12b28b","dweb:/ipfs/QmR6VvQs54XKH67DyWrWdLBf2n6XTYnTjRniY4CFihZAVN"],"license":"UNLICENSED"}},"version":1},"id":49}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea26469706673582212203b495f7bb157deb0060a295e9dac267b9d7e9e99d58b6b261eb376f830bcfe5864736f6c634300081e0033","sourceMap":"265:8588:43:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea26469706673582212203b495f7bb157deb0060a295e9dac267b9d7e9e99d58b6b261eb376f830bcfe5864736f6c634300081e0033","sourceMap":"265:8588: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\":\"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\":\"0xb3df5a014bbb48a1aea62faee4ef9c7a830fcb0209cf1304bdca4fa68126a3f3\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://b05b0c09bb8883fed3c03509bf6f5f9991435ae6648530662b4fd01f667ab955\",\"dweb:/ipfs/QmeYVgnoXn3uiZdUsW2TYigfRPuHBR7AV1fpRm6uT9Z1gZ\"]},\"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":"0xb3df5a014bbb48a1aea62faee4ef9c7a830fcb0209cf1304bdca4fa68126a3f3","urls":["bzz-raw://b05b0c09bb8883fed3c03509bf6f5f9991435ae6648530662b4fd01f667ab955","dweb:/ipfs/QmeYVgnoXn3uiZdUsW2TYigfRPuHBR7AV1fpRm6uT9Z1gZ"],"license":"UNLICENSED"},"src/LMSRStabilizedBalancedPair.sol":{"keccak256":"0x782f3baf92f74152c0b93b95199abbb3a36c75c921454260c8b0237f91d7c59d","urls":["bzz-raw://04d463c4fdcb6c8e2ebf9aed649ff21cca759ba73a4c93659e30c7df25e26c81","dweb:/ipfs/QmUxmWytiw5VYJRUrFbSGm1oWmDPQ4q23pnkmK1q9P4apN"],"license":"UNLICENSED"}},"version":1},"id":43} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220817e13d5a211c83f1cce4a24c79906e9de6370aad890508ad9f08db544c1e07c64736f6c634300081e0033","sourceMap":"265:8548:50:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220817e13d5a211c83f1cce4a24c79906e9de6370aad890508ad9f08db544c1e07c64736f6c634300081e0033","sourceMap":"265:8548:50:-: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\":\"0xfbb5d611a105095a9ccc71f859908eec12ed7df4573a787e130bbaf9fbaa7935\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://4f37e539fdbedd38488f5c5f0c8a4f579693e8de1ca546b60c580d4d0e12b28b\",\"dweb:/ipfs/QmR6VvQs54XKH67DyWrWdLBf2n6XTYnTjRniY4CFihZAVN\"]},\"src/LMSRStabilizedBalancedPair.sol\":{\"keccak256\":\"0x65a16365ae6dda4b5041f065aacc80661a9f9ef795e2be8930a7e89ad52d2cb0\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://90fc178c2f8ad02e30ce0da5b5e4e46c4c0be1d00149372bf9c9e89fbf585766\",\"dweb:/ipfs/QmPajJdZiy4CzrU8A8HonpU3WtjFL4BqR3eKVMwej3GQdh\"]}},\"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":"0xfbb5d611a105095a9ccc71f859908eec12ed7df4573a787e130bbaf9fbaa7935","urls":["bzz-raw://4f37e539fdbedd38488f5c5f0c8a4f579693e8de1ca546b60c580d4d0e12b28b","dweb:/ipfs/QmR6VvQs54XKH67DyWrWdLBf2n6XTYnTjRniY4CFihZAVN"],"license":"UNLICENSED"},"src/LMSRStabilizedBalancedPair.sol":{"keccak256":"0x65a16365ae6dda4b5041f065aacc80661a9f9ef795e2be8930a7e89ad52d2cb0","urls":["bzz-raw://90fc178c2f8ad02e30ce0da5b5e4e46c4c0be1d00149372bf9c9e89fbf585766","dweb:/ipfs/QmPajJdZiy4CzrU8A8HonpU3WtjFL4BqR3eKVMwej3GQdh"],"license":"UNLICENSED"}},"version":1},"id":50}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220ff1724fa31d9e324ea702ba224919eb915aeafa31fa3c696ca265c0e46de134064736f6c634300081e0033","sourceMap":"348:5083:30:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220ff1724fa31d9e324ea702ba224919eb915aeafa31fa3c696ca265c0e46de134064736f6c634300081e0033","sourceMap":"348:5083:30:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library of low level call functions that implement different calling strategies to deal with the return data. WARNING: Using this library requires an advanced understanding of Solidity and how the EVM works. It is recommended to use the {Address} library instead.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol\":\"LowLevelCall\"},\"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/openzeppelin-contracts/contracts/utils/LowLevelCall.sol\":{\"keccak256\":\"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848\",\"dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4\"]}},\"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":{"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol":"LowLevelCall"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol":{"keccak256":"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5","urls":["bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848","dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4"],"license":"MIT"}},"version":1},"id":30} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220ff1724fa31d9e324ea702ba224919eb915aeafa31fa3c696ca265c0e46de134064736f6c634300081e0033","sourceMap":"348:5083:36:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220ff1724fa31d9e324ea702ba224919eb915aeafa31fa3c696ca265c0e46de134064736f6c634300081e0033","sourceMap":"348:5083:36:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library of low level call functions that implement different calling strategies to deal with the return data. WARNING: Using this library requires an advanced understanding of Solidity and how the EVM works. It is recommended to use the {Address} library instead.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol\":\"LowLevelCall\"},\"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/openzeppelin-contracts/contracts/utils/LowLevelCall.sol\":{\"keccak256\":\"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848\",\"dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4\"]}},\"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":{"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol":"LowLevelCall"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/LowLevelCall.sol":{"keccak256":"0x50e81a8b089e3f382b6c915aa0166773de64ea4756e8f9479d9943a5f956ddf5","urls":["bzz-raw://bfeb96a150537222e2191c03887127499a4f21dfb5f9a7211da4d81749b52848","dweb:/ipfs/QmYR75ECbsBuxSiXmGvGfNKJRLoK5MdLUZL1bd8SixzxL4"],"license":"MIT"}},"version":1},"id":36}

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":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"OpenZeppelin's Ownable contract, split into internal and external parts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/OwnableInternal.sol\":\"OwnableInternal\"},\"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/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]},\"src/IOwnable.sol\":{\"keccak256\":\"0x7462267790c0d2312be1cbce077e5565aa86dac0789718c87ad0948174ecb990\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7eca10ffa6a7985d11eb476a351b1c09701056b0bdf8146612173bb19764e3f1\",\"dweb:/ipfs/QmTPF85yFSL3jDt2atZDLT4RV3zs8ch8P3G7YzCUiU8gR9\"]},\"src/OwnableInternal.sol\":{\"keccak256\":\"0x4dd94a81962a9708a07fdeba0f2b63bb5e17ef22f3b7a4d1e6afc5e589f95581\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://efecf80e2ef5afc06fb1f201270a41e15bed831275650d0e47c0d933e7b192ca\",\"dweb:/ipfs/QmNo4q3htXm758T8tKruR671mrDL2K1kkzRJjSKr7BTuiE\"]}},\"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/OwnableInternal.sol":"OwnableInternal"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"keccak256":"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2","urls":["bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12","dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF"],"license":"MIT"},"src/IOwnable.sol":{"keccak256":"0x7462267790c0d2312be1cbce077e5565aa86dac0789718c87ad0948174ecb990","urls":["bzz-raw://7eca10ffa6a7985d11eb476a351b1c09701056b0bdf8146612173bb19764e3f1","dweb:/ipfs/QmTPF85yFSL3jDt2atZDLT4RV3zs8ch8P3G7YzCUiU8gR9"],"license":"MIT"},"src/OwnableInternal.sol":{"keccak256":"0x4dd94a81962a9708a07fdeba0f2b63bb5e17ef22f3b7a4d1e6afc5e589f95581","urls":["bzz-raw://efecf80e2ef5afc06fb1f201270a41e15bed831275650d0e47c0d933e7b192ca","dweb:/ipfs/QmNo4q3htXm758T8tKruR671mrDL2K1kkzRJjSKr7BTuiE"],"license":"MIT"}},"version":1},"id":46} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"OpenZeppelin's Ownable contract, split into internal and external parts.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/OwnableInternal.sol\":\"OwnableInternal\"},\"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/openzeppelin-contracts/contracts/utils/Context.sol\":{\"keccak256\":\"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12\",\"dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF\"]},\"src/IOwnable.sol\":{\"keccak256\":\"0x7462267790c0d2312be1cbce077e5565aa86dac0789718c87ad0948174ecb990\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://7eca10ffa6a7985d11eb476a351b1c09701056b0bdf8146612173bb19764e3f1\",\"dweb:/ipfs/QmTPF85yFSL3jDt2atZDLT4RV3zs8ch8P3G7YzCUiU8gR9\"]},\"src/OwnableInternal.sol\":{\"keccak256\":\"0x4dd94a81962a9708a07fdeba0f2b63bb5e17ef22f3b7a4d1e6afc5e589f95581\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://efecf80e2ef5afc06fb1f201270a41e15bed831275650d0e47c0d933e7b192ca\",\"dweb:/ipfs/QmNo4q3htXm758T8tKruR671mrDL2K1kkzRJjSKr7BTuiE\"]}},\"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/OwnableInternal.sol":"OwnableInternal"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/Context.sol":{"keccak256":"0x493033a8d1b176a037b2cc6a04dad01a5c157722049bbecf632ca876224dd4b2","urls":["bzz-raw://6a708e8a5bdb1011c2c381c9a5cfd8a9a956d7d0a9dc1bd8bcdaf52f76ef2f12","dweb:/ipfs/Qmax9WHBnVsZP46ZxEMNRQpLQnrdE4dK8LehML1Py8FowF"],"license":"MIT"},"src/IOwnable.sol":{"keccak256":"0x7462267790c0d2312be1cbce077e5565aa86dac0789718c87ad0948174ecb990","urls":["bzz-raw://7eca10ffa6a7985d11eb476a351b1c09701056b0bdf8146612173bb19764e3f1","dweb:/ipfs/QmTPF85yFSL3jDt2atZDLT4RV3zs8ch8P3G7YzCUiU8gR9"],"license":"MIT"},"src/OwnableInternal.sol":{"keccak256":"0x4dd94a81962a9708a07fdeba0f2b63bb5e17ef22f3b7a4d1e6afc5e589f95581","urls":["bzz-raw://efecf80e2ef5afc06fb1f201270a41e15bed831275650d0e47c0d933e7b192ca","dweb:/ipfs/QmNo4q3htXm758T8tKruR671mrDL2K1kkzRJjSKr7BTuiE"],"license":"MIT"}},"version":1},"id":53}

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 @@
{"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/PartyPoolHelpers.sol\":\"PartyPoolHelpers\"},\"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/PartyPoolHelpers.sol\":{\"keccak256\":\"0xd43b635d12b6684ae38a685eea4bc5783cebb3696514d8aafe3f4ce34f5e759c\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://832046b365d443c4c1c715f98fe3de224e3ba82c67960053d51e6a79847c4af5\",\"dweb:/ipfs/QmZ4nWMwyYQzaBGF7rBE73GYTs4z3DRNYL1ZrGAsxN6RfP\"]}},\"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/PartyPoolHelpers.sol":"PartyPoolHelpers"},"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/PartyPoolHelpers.sol":{"keccak256":"0xd43b635d12b6684ae38a685eea4bc5783cebb3696514d8aafe3f4ce34f5e759c","urls":["bzz-raw://832046b365d443c4c1c715f98fe3de224e3ba82c67960053d51e6a79847c4af5","dweb:/ipfs/QmZ4nWMwyYQzaBGF7rBE73GYTs4z3DRNYL1ZrGAsxN6RfP"],"license":"UNLICENSED"}},"version":1},"id":52} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/PartyPoolHelpers.sol\":\"PartyPoolHelpers\"},\"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/PartyPoolHelpers.sol\":{\"keccak256\":\"0xd43b635d12b6684ae38a685eea4bc5783cebb3696514d8aafe3f4ce34f5e759c\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://832046b365d443c4c1c715f98fe3de224e3ba82c67960053d51e6a79847c4af5\",\"dweb:/ipfs/QmZ4nWMwyYQzaBGF7rBE73GYTs4z3DRNYL1ZrGAsxN6RfP\"]}},\"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/PartyPoolHelpers.sol":"PartyPoolHelpers"},"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/PartyPoolHelpers.sol":{"keccak256":"0xd43b635d12b6684ae38a685eea4bc5783cebb3696514d8aafe3f4ce34f5e759c","urls":["bzz-raw://832046b365d443c4c1c715f98fe3de224e3ba82c67960053d51e6a79847c4af5","dweb:/ipfs/QmZ4nWMwyYQzaBGF7rBE73GYTs4z3DRNYL1ZrGAsxN6RfP"],"license":"UNLICENSED"}},"version":1},"id":59}

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":[{"type":"fallback","stateMutability":"payable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"stateMutability\":\"payable\",\"type\":\"fallback\"}],\"devdoc\":{\"details\":\"This abstract contract provides a fallback function that delegates all calls to another contract using the EVM instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to be specified by overriding the virtual {_implementation} function. Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a different contract through the {_delegate} function. The success and return data of the delegated call will be returned back to the caller of the proxy.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/proxy/Proxy.sol\":\"Proxy\"},\"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/openzeppelin-contracts/contracts/proxy/Proxy.sol\":{\"keccak256\":\"0x25f9b099413f805b4c4bbad8cc179326c10be237aec00349caf91524f8db0bbc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://dcfb75af07ad33b1f8e966f793db3df8fbcfb14103ed3644c0c634658a8fd099\",\"dweb:/ipfs/QmPWamdkbcKwG3ah2G9TZtKHzQmjnunsWoPWr5KKfbrKNb\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"payable","type":"fallback"}],"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":{"lib/openzeppelin-contracts/contracts/proxy/Proxy.sol":"Proxy"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/proxy/Proxy.sol":{"keccak256":"0x25f9b099413f805b4c4bbad8cc179326c10be237aec00349caf91524f8db0bbc","urls":["bzz-raw://dcfb75af07ad33b1f8e966f793db3df8fbcfb14103ed3644c0c634658a8fd099","dweb:/ipfs/QmPWamdkbcKwG3ah2G9TZtKHzQmjnunsWoPWr5KKfbrKNb"],"license":"MIT"}},"version":1},"id":22} {"abi":[{"type":"fallback","stateMutability":"payable"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"stateMutability\":\"payable\",\"type\":\"fallback\"}],\"devdoc\":{\"details\":\"This abstract contract provides a fallback function that delegates all calls to another contract using the EVM instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to be specified by overriding the virtual {_implementation} function. Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a different contract through the {_delegate} function. The success and return data of the delegated call will be returned back to the caller of the proxy.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/proxy/Proxy.sol\":\"Proxy\"},\"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/openzeppelin-contracts/contracts/proxy/Proxy.sol\":{\"keccak256\":\"0x25f9b099413f805b4c4bbad8cc179326c10be237aec00349caf91524f8db0bbc\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://dcfb75af07ad33b1f8e966f793db3df8fbcfb14103ed3644c0c634658a8fd099\",\"dweb:/ipfs/QmPWamdkbcKwG3ah2G9TZtKHzQmjnunsWoPWr5KKfbrKNb\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"payable","type":"fallback"}],"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":{"lib/openzeppelin-contracts/contracts/proxy/Proxy.sol":"Proxy"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/proxy/Proxy.sol":{"keccak256":"0x25f9b099413f805b4c4bbad8cc179326c10be237aec00349caf91524f8db0bbc","urls":["bzz-raw://dcfb75af07ad33b1f8e966f793db3df8fbcfb14103ed3644c0c634658a8fd099","dweb:/ipfs/QmPWamdkbcKwG3ah2G9TZtKHzQmjnunsWoPWr5KKfbrKNb"],"license":"MIT"}},"version":1},"id":28}

View File

@@ -1 +1 @@
{"abi":[{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"ReentrancyGuardReentrantCall\",\"type\":\"error\"}],\"devdoc\":{\"custom:stateless\":\"\",\"details\":\"Contract module that helps prevent reentrant calls to a function. Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier available, which can be applied to functions to make sure there are no nested (reentrant) calls to them. Note that because there is a single `nonReentrant` guard, functions marked as `nonReentrant` may not call one another. This can be worked around by making those functions `private`, and then adding `external` `nonReentrant` entry points to them. TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, consider using {ReentrancyGuardTransient} instead. TIP: If you would like to learn more about reentrancy and alternative ways to protect against it, check out our blog post https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced by the {ReentrancyGuardTransient} variant in v6.0.\",\"errors\":{\"ReentrancyGuardReentrantCall()\":[{\"details\":\"Unauthorized reentrant call.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol\":\"ReentrancyGuard\"},\"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/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol\":{\"keccak256\":\"0x6f9ed073e3dab12233a79cd85153f72c9e0f99c1f5512f6d5b1ef09fb46abbb0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://093d2a804b792a0000883c2215585963ed98ec4341b45bc4224844623387d161\",\"dweb:/ipfs/QmR5shjVosAoxdmY3EfkUWgFNV4CVUcbRNS7tkvbipssPX\"]},\"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b\",\"dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[],"type":"error","name":"ReentrancyGuardReentrantCall"}],"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":{"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol":"ReentrancyGuard"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol":{"keccak256":"0x6f9ed073e3dab12233a79cd85153f72c9e0f99c1f5512f6d5b1ef09fb46abbb0","urls":["bzz-raw://093d2a804b792a0000883c2215585963ed98ec4341b45bc4224844623387d161","dweb:/ipfs/QmR5shjVosAoxdmY3EfkUWgFNV4CVUcbRNS7tkvbipssPX"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"keccak256":"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97","urls":["bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b","dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM"],"license":"MIT"}},"version":1},"id":31} {"abi":[{"type":"error","name":"ReentrancyGuardReentrantCall","inputs":[]}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"ReentrancyGuardReentrantCall\",\"type\":\"error\"}],\"devdoc\":{\"custom:stateless\":\"\",\"details\":\"Contract module that helps prevent reentrant calls to a function. Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier available, which can be applied to functions to make sure there are no nested (reentrant) calls to them. Note that because there is a single `nonReentrant` guard, functions marked as `nonReentrant` may not call one another. This can be worked around by making those functions `private`, and then adding `external` `nonReentrant` entry points to them. TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at, consider using {ReentrancyGuardTransient} instead. TIP: If you would like to learn more about reentrancy and alternative ways to protect against it, check out our blog post https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced by the {ReentrancyGuardTransient} variant in v6.0.\",\"errors\":{\"ReentrancyGuardReentrantCall()\":[{\"details\":\"Unauthorized reentrant call.\"}]},\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol\":\"ReentrancyGuard\"},\"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/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol\":{\"keccak256\":\"0x6f9ed073e3dab12233a79cd85153f72c9e0f99c1f5512f6d5b1ef09fb46abbb0\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://093d2a804b792a0000883c2215585963ed98ec4341b45bc4224844623387d161\",\"dweb:/ipfs/QmR5shjVosAoxdmY3EfkUWgFNV4CVUcbRNS7tkvbipssPX\"]},\"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b\",\"dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.30+commit.73712a01"},"language":"Solidity","output":{"abi":[{"inputs":[],"type":"error","name":"ReentrancyGuardReentrantCall"}],"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":{"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol":"ReentrancyGuard"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol":{"keccak256":"0x6f9ed073e3dab12233a79cd85153f72c9e0f99c1f5512f6d5b1ef09fb46abbb0","urls":["bzz-raw://093d2a804b792a0000883c2215585963ed98ec4341b45bc4224844623387d161","dweb:/ipfs/QmR5shjVosAoxdmY3EfkUWgFNV4CVUcbRNS7tkvbipssPX"],"license":"MIT"},"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"keccak256":"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97","urls":["bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b","dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM"],"license":"MIT"}},"version":1},"id":37}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","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\":\"StdChains provides information about EVM compatible chains that can be used in scripts/tests. For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the alias used in this contract, which can be found as the first argument to the `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function. There are two main ways to use this contract: 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or `setChain(string memory chainAlias, Chain memory chain)` 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. The first time either of those are used, chains are initialized with the default set of RPC URLs. This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in `defaultRpcUrls`. The `setChain` function is straightforward, and it simply saves off the given chain data. The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say we want to retrieve the RPC URL for `mainnet`: - If you have specified data with `setChain`, it will return that. - If you have configured a mainnet RPC URL in `foundry.toml`, it will return the URL, provided it is valid (e.g. a URL is specified, or an environment variable is given and exists). - If neither of the above conditions is met, the default data is returned. Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdChains.sol\":\"StdChains\"},\"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/forge-std/src/StdChains.sol\":{\"keccak256\":\"0xb2cbca1a6ffa19926c31bad47393a070305c809fe5d88c52214d5c51ce0733c6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cf20975cfd9733910305fc8e746c7631c2ab210289aab036cec32f3c530335c7\",\"dweb:/ipfs/QmYYvVzvAN1uCt8XtDmWo5x2inSVJBYajFexe92rVWEuMf\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdChains.sol":"StdChains"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdChains.sol":{"keccak256":"0xb2cbca1a6ffa19926c31bad47393a070305c809fe5d88c52214d5c51ce0733c6","urls":["bzz-raw://cf20975cfd9733910305fc8e746c7631c2ab210289aab036cec32f3c530335c7","dweb:/ipfs/QmYYvVzvAN1uCt8XtDmWo5x2inSVJBYajFexe92rVWEuMf"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":3} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","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\":\"StdChains provides information about EVM compatible chains that can be used in scripts/tests. For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the alias used in this contract, which can be found as the first argument to the `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function. There are two main ways to use this contract: 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or `setChain(string memory chainAlias, Chain memory chain)` 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. The first time either of those are used, chains are initialized with the default set of RPC URLs. This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in `defaultRpcUrls`. The `setChain` function is straightforward, and it simply saves off the given chain data. The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say we want to retrieve the RPC URL for `mainnet`: - If you have specified data with `setChain`, it will return that. - If you have configured a mainnet RPC URL in `foundry.toml`, it will return the URL, provided it is valid (e.g. a URL is specified, or an environment variable is given and exists). - If neither of the above conditions is met, the default data is returned. Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdChains.sol\":\"StdChains\"},\"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/forge-std/src/StdChains.sol\":{\"keccak256\":\"0xb2cbca1a6ffa19926c31bad47393a070305c809fe5d88c52214d5c51ce0733c6\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cf20975cfd9733910305fc8e746c7631c2ab210289aab036cec32f3c530335c7\",\"dweb:/ipfs/QmYYvVzvAN1uCt8XtDmWo5x2inSVJBYajFexe92rVWEuMf\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdChains.sol":"StdChains"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdChains.sol":{"keccak256":"0xb2cbca1a6ffa19926c31bad47393a070305c809fe5d88c52214d5c51ce0733c6","urls":["bzz-raw://cf20975cfd9733910305fc8e746c7631c2ab210289aab036cec32f3c530335c7","dweb:/ipfs/QmYYvVzvAN1uCt8XtDmWo5x2inSVJBYajFexe92rVWEuMf"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":4}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdCheats.sol\":\"StdCheats\"},\"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/forge-std/src/StdCheats.sol\":{\"keccak256\":\"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41\",\"dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK\"]},\"lib/forge-std/src/StdStorage.sol\":{\"keccak256\":\"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc\",\"dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]},\"lib/forge-std/src/console.sol\":{\"keccak256\":\"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57\",\"dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP\"]},\"lib/forge-std/src/console2.sol\":{\"keccak256\":\"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d\",\"dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ\"]}},\"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":{"lib/forge-std/src/StdCheats.sol":"StdCheats"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdCheats.sol":{"keccak256":"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746","urls":["bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41","dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK"],"license":"MIT"},"lib/forge-std/src/StdStorage.sol":{"keccak256":"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd","urls":["bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc","dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"},"lib/forge-std/src/console.sol":{"keccak256":"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5","urls":["bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57","dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP"],"license":"MIT"},"lib/forge-std/src/console2.sol":{"keccak256":"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f","urls":["bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d","dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ"],"license":"MIT"}},"version":1},"id":4} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdCheats.sol\":\"StdCheats\"},\"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/forge-std/src/StdCheats.sol\":{\"keccak256\":\"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41\",\"dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK\"]},\"lib/forge-std/src/StdStorage.sol\":{\"keccak256\":\"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc\",\"dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]},\"lib/forge-std/src/console.sol\":{\"keccak256\":\"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57\",\"dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP\"]},\"lib/forge-std/src/console2.sol\":{\"keccak256\":\"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d\",\"dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ\"]}},\"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":{"lib/forge-std/src/StdCheats.sol":"StdCheats"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdCheats.sol":{"keccak256":"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746","urls":["bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41","dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK"],"license":"MIT"},"lib/forge-std/src/StdStorage.sol":{"keccak256":"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd","urls":["bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc","dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"},"lib/forge-std/src/console.sol":{"keccak256":"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5","urls":["bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57","dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP"],"license":"MIT"},"lib/forge-std/src/console2.sol":{"keccak256":"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f","urls":["bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d","dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ"],"license":"MIT"}},"version":1},"id":5}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdCheats.sol\":\"StdCheatsSafe\"},\"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/forge-std/src/StdCheats.sol\":{\"keccak256\":\"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41\",\"dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK\"]},\"lib/forge-std/src/StdStorage.sol\":{\"keccak256\":\"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc\",\"dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]},\"lib/forge-std/src/console.sol\":{\"keccak256\":\"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57\",\"dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP\"]},\"lib/forge-std/src/console2.sol\":{\"keccak256\":\"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d\",\"dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ\"]}},\"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":{"lib/forge-std/src/StdCheats.sol":"StdCheatsSafe"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdCheats.sol":{"keccak256":"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746","urls":["bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41","dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK"],"license":"MIT"},"lib/forge-std/src/StdStorage.sol":{"keccak256":"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd","urls":["bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc","dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"},"lib/forge-std/src/console.sol":{"keccak256":"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5","urls":["bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57","dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP"],"license":"MIT"},"lib/forge-std/src/console2.sol":{"keccak256":"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f","urls":["bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d","dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ"],"license":"MIT"}},"version":1},"id":4} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdCheats.sol\":\"StdCheatsSafe\"},\"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/forge-std/src/StdCheats.sol\":{\"keccak256\":\"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41\",\"dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK\"]},\"lib/forge-std/src/StdStorage.sol\":{\"keccak256\":\"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc\",\"dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]},\"lib/forge-std/src/console.sol\":{\"keccak256\":\"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57\",\"dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP\"]},\"lib/forge-std/src/console2.sol\":{\"keccak256\":\"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d\",\"dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ\"]}},\"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":{"lib/forge-std/src/StdCheats.sol":"StdCheatsSafe"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdCheats.sol":{"keccak256":"0x0fa6ec03602648b62cce41aab2096e6b7e052f2846075d967b6958dd586db746","urls":["bzz-raw://cd84e2ca9c1eaed6b76768cc12bb8c1af8289170ea8b7706f58d516460d79c41","dweb:/ipfs/QmQ7BK7co6DE4eWUqMyv11s5eHYkS1tyx8tDSZGZVtf2aK"],"license":"MIT"},"lib/forge-std/src/StdStorage.sol":{"keccak256":"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd","urls":["bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc","dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"},"lib/forge-std/src/console.sol":{"keccak256":"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5","urls":["bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57","dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP"],"license":"MIT"},"lib/forge-std/src/console2.sol":{"keccak256":"0x3b8fe79f48f065a4e4d35362171304a33784c3a90febae5f2787805a438de12f","urls":["bzz-raw://61de63af08803549299e68b6e6e88d40f3c5afac450e4ee0a228c66a61ba003d","dweb:/ipfs/QmWVoQ5rrVxnczD4ZZoPbD4PC9Z3uExJtzjD4awTqd14MZ"],"license":"MIT"}},"version":1},"id":5}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220f305db5938071a82ff12d5cca101765d7bc698c9c34558487d9c37f2ce06498864736f6c634300081e0033","sourceMap":"610:9092:6:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220f305db5938071a82ff12d5cca101765d7bc698c9c34558487d9c37f2ce06498864736f6c634300081e0033","sourceMap":"610:9092:6:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdJson.sol\":\"stdJson\"},\"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/forge-std/src/StdJson.sol\":{\"keccak256\":\"0xbc0132abe1c2accc2867c0f03667afffdf92f3e95a581bb03c9557eaa38ea500\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://eb6fab37dc73c219cfbb7b4f4998bcf7677ca5397a867e850f40232192073974\",\"dweb:/ipfs/QmUHsbVdp9SKmgek7ZfPcLTKrpZFXpqaqt4sVejzxGEQL3\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdJson.sol":"stdJson"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdJson.sol":{"keccak256":"0xbc0132abe1c2accc2867c0f03667afffdf92f3e95a581bb03c9557eaa38ea500","urls":["bzz-raw://eb6fab37dc73c219cfbb7b4f4998bcf7677ca5397a867e850f40232192073974","dweb:/ipfs/QmUHsbVdp9SKmgek7ZfPcLTKrpZFXpqaqt4sVejzxGEQL3"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":6} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220f305db5938071a82ff12d5cca101765d7bc698c9c34558487d9c37f2ce06498864736f6c634300081e0033","sourceMap":"610:9092:9:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220f305db5938071a82ff12d5cca101765d7bc698c9c34558487d9c37f2ce06498864736f6c634300081e0033","sourceMap":"610:9092:9:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdJson.sol\":\"stdJson\"},\"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/forge-std/src/StdJson.sol\":{\"keccak256\":\"0xbc0132abe1c2accc2867c0f03667afffdf92f3e95a581bb03c9557eaa38ea500\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://eb6fab37dc73c219cfbb7b4f4998bcf7677ca5397a867e850f40232192073974\",\"dweb:/ipfs/QmUHsbVdp9SKmgek7ZfPcLTKrpZFXpqaqt4sVejzxGEQL3\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdJson.sol":"stdJson"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdJson.sol":{"keccak256":"0xbc0132abe1c2accc2867c0f03667afffdf92f3e95a581bb03c9557eaa38ea500","urls":["bzz-raw://eb6fab37dc73c219cfbb7b4f4998bcf7677ca5397a867e850f40232192073974","dweb:/ipfs/QmUHsbVdp9SKmgek7ZfPcLTKrpZFXpqaqt4sVejzxGEQL3"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":9}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220adcf8debe9b04ab23be8899f7649898efd38d0c0661f99c6186f371e6c71255d64736f6c634300081e0033","sourceMap":"65:1533:7:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220adcf8debe9b04ab23be8899f7649898efd38d0c0661f99c6186f371e6c71255d64736f6c634300081e0033","sourceMap":"65:1533:7:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdMath.sol\":\"stdMath\"},\"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/forge-std/src/StdMath.sol\":{\"keccak256\":\"0xcb876f5421e5aae334f9a6c5d549131c18ad347f1035d2a1e920f2623f346c85\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://28076e06b01be4095f860fa9b142c284bac34c0813948e0a52d11acc15502db6\",\"dweb:/ipfs/QmVR6XFTmBatJAVvYgkZxN21R5zvYTU4ard4Aow8TmXjy9\"]}},\"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":{"lib/forge-std/src/StdMath.sol":"stdMath"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdMath.sol":{"keccak256":"0xcb876f5421e5aae334f9a6c5d549131c18ad347f1035d2a1e920f2623f346c85","urls":["bzz-raw://28076e06b01be4095f860fa9b142c284bac34c0813948e0a52d11acc15502db6","dweb:/ipfs/QmVR6XFTmBatJAVvYgkZxN21R5zvYTU4ard4Aow8TmXjy9"],"license":"MIT"}},"version":1},"id":7} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220adcf8debe9b04ab23be8899f7649898efd38d0c0661f99c6186f371e6c71255d64736f6c634300081e0033","sourceMap":"65:1533:10:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220adcf8debe9b04ab23be8899f7649898efd38d0c0661f99c6186f371e6c71255d64736f6c634300081e0033","sourceMap":"65:1533:10:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdMath.sol\":\"stdMath\"},\"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/forge-std/src/StdMath.sol\":{\"keccak256\":\"0xcb876f5421e5aae334f9a6c5d549131c18ad347f1035d2a1e920f2623f346c85\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://28076e06b01be4095f860fa9b142c284bac34c0813948e0a52d11acc15502db6\",\"dweb:/ipfs/QmVR6XFTmBatJAVvYgkZxN21R5zvYTU4ard4Aow8TmXjy9\"]}},\"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":{"lib/forge-std/src/StdMath.sol":"stdMath"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdMath.sol":{"keccak256":"0xcb876f5421e5aae334f9a6c5d549131c18ad347f1035d2a1e920f2623f346c85","urls":["bzz-raw://28076e06b01be4095f860fa9b142c284bac34c0813948e0a52d11acc15502db6","dweb:/ipfs/QmVR6XFTmBatJAVvYgkZxN21R5zvYTU4ard4Aow8TmXjy9"],"license":"MIT"}},"version":1},"id":10}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea26469706673582212205da5662f9d842c8ded410a0b709c832567faa4171dcdb71541befdbf20e9a73964736f6c634300081e0033","sourceMap":"12755:5081:8:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea26469706673582212205da5662f9d842c8ded410a0b709c832567faa4171dcdb71541befdbf20e9a73964736f6c634300081e0033","sourceMap":"12755:5081:8:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdStorage.sol\":\"stdStorage\"},\"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/forge-std/src/StdStorage.sol\":{\"keccak256\":\"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc\",\"dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdStorage.sol":"stdStorage"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdStorage.sol":{"keccak256":"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd","urls":["bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc","dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":8} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea26469706673582212205da5662f9d842c8ded410a0b709c832567faa4171dcdb71541befdbf20e9a73964736f6c634300081e0033","sourceMap":"12755:5081:11:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea26469706673582212205da5662f9d842c8ded410a0b709c832567faa4171dcdb71541befdbf20e9a73964736f6c634300081e0033","sourceMap":"12755:5081:11:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdStorage.sol\":\"stdStorage\"},\"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/forge-std/src/StdStorage.sol\":{\"keccak256\":\"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc\",\"dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdStorage.sol":"stdStorage"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdStorage.sol":{"keccak256":"0x04102de0a79398e4bdea57b7a4818655b4cc66d6f81d1cff08bf428cd0b384cd","urls":["bzz-raw://53edc6c8f7f67cafc0129f039637c77d979880f7f1947defea31e8f0c05095bc","dweb:/ipfs/QmUKXJd1vFCkxxrkXNLURdXrx2apoyWQFrFb5UqNkjdHVi"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":11}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea26469706673582212200129420999a12c7d2a0dfd6cc82ba6ee0da34a58e359b77d477502f6d9c20a6964736f6c634300081e0033","sourceMap":"100:10361:9:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea26469706673582212200129420999a12c7d2a0dfd6cc82ba6ee0da34a58e359b77d477502f6d9c20a6964736f6c634300081e0033","sourceMap":"100:10361:9:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdStyle.sol\":\"StdStyle\"},\"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/forge-std/src/StdStyle.sol\":{\"keccak256\":\"0x43e2a8a9b9c2574dabe74f11adf6f782df218f463540e3b5b563609fe108597d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://51363ca97404cf4128e1141428949768c31929e75e014b02c85e887fbbb4f1b8\",\"dweb:/ipfs/QmVhtbQc2fU4rRmbcfBtz34mAgG4BAZBsbna1Ca4SkoPsK\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdStyle.sol":"StdStyle"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdStyle.sol":{"keccak256":"0x43e2a8a9b9c2574dabe74f11adf6f782df218f463540e3b5b563609fe108597d","urls":["bzz-raw://51363ca97404cf4128e1141428949768c31929e75e014b02c85e887fbbb4f1b8","dweb:/ipfs/QmVhtbQc2fU4rRmbcfBtz34mAgG4BAZBsbna1Ca4SkoPsK"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":9} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea26469706673582212200129420999a12c7d2a0dfd6cc82ba6ee0da34a58e359b77d477502f6d9c20a6964736f6c634300081e0033","sourceMap":"100:10361:12:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea26469706673582212200129420999a12c7d2a0dfd6cc82ba6ee0da34a58e359b77d477502f6d9c20a6964736f6c634300081e0033","sourceMap":"100:10361:12:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdStyle.sol\":\"StdStyle\"},\"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/forge-std/src/StdStyle.sol\":{\"keccak256\":\"0x43e2a8a9b9c2574dabe74f11adf6f782df218f463540e3b5b563609fe108597d\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://51363ca97404cf4128e1141428949768c31929e75e014b02c85e887fbbb4f1b8\",\"dweb:/ipfs/QmVhtbQc2fU4rRmbcfBtz34mAgG4BAZBsbna1Ca4SkoPsK\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]}},\"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":{"lib/forge-std/src/StdStyle.sol":"StdStyle"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdStyle.sol":{"keccak256":"0x43e2a8a9b9c2574dabe74f11adf6f782df218f463540e3b5b563609fe108597d","urls":["bzz-raw://51363ca97404cf4128e1141428949768c31929e75e014b02c85e887fbbb4f1b8","dweb:/ipfs/QmVhtbQc2fU4rRmbcfBtz34mAgG4BAZBsbna1Ca4SkoPsK"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"}},"version":1},"id":12}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdUtils.sol\":\"StdUtils\"},\"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/forge-std/src/StdUtils.sol\":{\"keccak256\":\"0xb2469a902a326074034c4f7081d868113db0edbb7cf48b86528af2d6b07295f8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1430a81c4978be875e2a3b31a8bfa4e1438fecd327f23771b690d64db63c020a\",\"dweb:/ipfs/QmW6aB2u1LNaRgGQFwjV7L7UbxsRg63iJ7AuujPouEa4cT\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]},\"lib/forge-std/src/interfaces/IMulticall3.sol\":{\"keccak256\":\"0x7aac1389150499a922d1f9ef5749c908cef127cb2075b92fa17e9cb611263d0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d95ebb7c7c463e08ebc12dab639945752fb2480acfc6e86da32f72732a7fd0c0\",\"dweb:/ipfs/QmNXK8P8oPWwajsQHvAHw3JPyQidPLCGQN3hWu1Lk6PBL2\"]}},\"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":{"lib/forge-std/src/StdUtils.sol":"StdUtils"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdUtils.sol":{"keccak256":"0xb2469a902a326074034c4f7081d868113db0edbb7cf48b86528af2d6b07295f8","urls":["bzz-raw://1430a81c4978be875e2a3b31a8bfa4e1438fecd327f23771b690d64db63c020a","dweb:/ipfs/QmW6aB2u1LNaRgGQFwjV7L7UbxsRg63iJ7AuujPouEa4cT"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"},"lib/forge-std/src/interfaces/IMulticall3.sol":{"keccak256":"0x7aac1389150499a922d1f9ef5749c908cef127cb2075b92fa17e9cb611263d0a","urls":["bzz-raw://d95ebb7c7c463e08ebc12dab639945752fb2480acfc6e86da32f72732a7fd0c0","dweb:/ipfs/QmNXK8P8oPWwajsQHvAHw3JPyQidPLCGQN3hWu1Lk6PBL2"],"license":"MIT"}},"version":1},"id":10} {"abi":[],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/StdUtils.sol\":\"StdUtils\"},\"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/forge-std/src/StdUtils.sol\":{\"keccak256\":\"0xb2469a902a326074034c4f7081d868113db0edbb7cf48b86528af2d6b07295f8\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://1430a81c4978be875e2a3b31a8bfa4e1438fecd327f23771b690d64db63c020a\",\"dweb:/ipfs/QmW6aB2u1LNaRgGQFwjV7L7UbxsRg63iJ7AuujPouEa4cT\"]},\"lib/forge-std/src/Vm.sol\":{\"keccak256\":\"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f\",\"license\":\"MIT OR Apache-2.0\",\"urls\":[\"bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f\",\"dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL\"]},\"lib/forge-std/src/interfaces/IMulticall3.sol\":{\"keccak256\":\"0x7aac1389150499a922d1f9ef5749c908cef127cb2075b92fa17e9cb611263d0a\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://d95ebb7c7c463e08ebc12dab639945752fb2480acfc6e86da32f72732a7fd0c0\",\"dweb:/ipfs/QmNXK8P8oPWwajsQHvAHw3JPyQidPLCGQN3hWu1Lk6PBL2\"]}},\"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":{"lib/forge-std/src/StdUtils.sol":"StdUtils"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/StdUtils.sol":{"keccak256":"0xb2469a902a326074034c4f7081d868113db0edbb7cf48b86528af2d6b07295f8","urls":["bzz-raw://1430a81c4978be875e2a3b31a8bfa4e1438fecd327f23771b690d64db63c020a","dweb:/ipfs/QmW6aB2u1LNaRgGQFwjV7L7UbxsRg63iJ7AuujPouEa4cT"],"license":"MIT"},"lib/forge-std/src/Vm.sol":{"keccak256":"0x9b4df44a3b748593a58be7ba64fa5f420e5dcd7927bfa5173186228bfe61782f","urls":["bzz-raw://b89fcf92ee1d14237cfb0dd949341053389d5b6a043ad77349b65bef80b1d59f","dweb:/ipfs/QmPkia3aNHrqvE4tqxG2AyrdB4W91jTAvcbchgs2wAo6NL"],"license":"MIT OR Apache-2.0"},"lib/forge-std/src/interfaces/IMulticall3.sol":{"keccak256":"0x7aac1389150499a922d1f9ef5749c908cef127cb2075b92fa17e9cb611263d0a","urls":["bzz-raw://d95ebb7c7c463e08ebc12dab639945752fb2480acfc6e86da32f72732a7fd0c0","dweb:/ipfs/QmNXK8P8oPWwajsQHvAHw3JPyQidPLCGQN3hWu1Lk6PBL2"],"license":"MIT"}},"version":1},"id":14}

View File

@@ -1 +1 @@
{"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220ea5a41e6dbc6ca08b6521f0969fc2f079cea68e510c192f94e81f843a5e6d3b264736f6c634300081e0033","sourceMap":"1407:2774:32:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220ea5a41e6dbc6ca08b6521f0969fc2f079cea68e510c192f94e81f843a5e6d3b264736f6c634300081e0033","sourceMap":"1407:2774:32:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for reading and writing primitive types to specific storage slots. Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. This library helps with reading and writing to such slots without the need for inline assembly. The functions in this library return Slot structs that contain a `value` member that can be used to read or write. Example usage to set ERC-1967 implementation slot: ```solidity contract ERC1967 { // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } function _setImplementation(address newImplementation) internal { require(newImplementation.code.length > 0); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } } ``` TIP: Consider using this library along with {SlotDerivation}.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":\"StorageSlot\"},\"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/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b\",\"dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM\"]}},\"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":{"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":"StorageSlot"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"keccak256":"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97","urls":["bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b","dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM"],"license":"MIT"}},"version":1},"id":32} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220ea5a41e6dbc6ca08b6521f0969fc2f079cea68e510c192f94e81f843a5e6d3b264736f6c634300081e0033","sourceMap":"1407:2774:38:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220ea5a41e6dbc6ca08b6521f0969fc2f079cea68e510c192f94e81f843a5e6d3b264736f6c634300081e0033","sourceMap":"1407:2774:38:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"details\":\"Library for reading and writing primitive types to specific storage slots. Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. This library helps with reading and writing to such slots without the need for inline assembly. The functions in this library return Slot structs that contain a `value` member that can be used to read or write. Example usage to set ERC-1967 implementation slot: ```solidity contract ERC1967 { // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } function _setImplementation(address newImplementation) internal { require(newImplementation.code.length > 0); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } } ``` TIP: Consider using this library along with {SlotDerivation}.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":\"StorageSlot\"},\"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/openzeppelin-contracts/contracts/utils/StorageSlot.sol\":{\"keccak256\":\"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b\",\"dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM\"]}},\"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":{"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":"StorageSlot"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol":{"keccak256":"0xcf74f855663ce2ae00ed8352666b7935f6cddea2932fdf2c3ecd30a9b1cd0e97","urls":["bzz-raw://9f660b1f351b757dfe01438e59888f31f33ded3afcf5cb5b0d9bf9aa6f320a8b","dweb:/ipfs/QmarDJ5hZEgBtCmmrVzEZWjub9769eD686jmzb2XpSU1cM"],"license":"MIT"}},"version":1},"id":38}

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":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220afc188cd5160e43f0d46902109404da8f6c8b1df4eb40d16374d9645b8ecd8c964736f6c634300081e0033","sourceMap":"66:69203:12:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220afc188cd5160e43f0d46902109404da8f6c8b1df4eb40d16374d9645b8ecd8c964736f6c634300081e0033","sourceMap":"66:69203:12:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/console.sol\":\"console\"},\"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/forge-std/src/console.sol\":{\"keccak256\":\"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57\",\"dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP\"]}},\"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":{"lib/forge-std/src/console.sol":"console"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/console.sol":{"keccak256":"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5","urls":["bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57","dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP"],"license":"MIT"}},"version":1},"id":12} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220afc188cd5160e43f0d46902109404da8f6c8b1df4eb40d16374d9645b8ecd8c964736f6c634300081e0033","sourceMap":"66:69203:17:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220afc188cd5160e43f0d46902109404da8f6c8b1df4eb40d16374d9645b8ecd8c964736f6c634300081e0033","sourceMap":"66:69203:17:-: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\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/console.sol\":\"console\"},\"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/forge-std/src/console.sol\":{\"keccak256\":\"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57\",\"dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP\"]}},\"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":{"lib/forge-std/src/console.sol":"console"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/console.sol":{"keccak256":"0x4bbf47eb762cef93729d6ef15e78789957147039b113e5d4df48e3d3fd16d0f5","urls":["bzz-raw://af9e3a7c3d82fb5b10b57ca4d1a82f2acbef80c077f6f6ef0cc0187c7bfd9f57","dweb:/ipfs/QmR9VzmnBDJpgiDP6CHT6truehukF9HpYvuP6kRiJbDwPP"],"license":"MIT"}},"version":1},"id":17}

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":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220709c8134992b5fef4e2bf94b521207862a1126f22dcc0c41899199d76b8ca7c164736f6c634300081e0033","sourceMap":"163:427371:15:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220709c8134992b5fef4e2bf94b521207862a1126f22dcc0c41899199d76b8ca7c164736f6c634300081e0033","sourceMap":"163:427371:15:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"author\":\"philogy <https://github.com/philogy>\",\"details\":\"Code generated automatically by script.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/safeconsole.sol\":\"safeconsole\"},\"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/forge-std/src/safeconsole.sol\":{\"keccak256\":\"0xbef9786cb49d3eade757bad87568c49c8c8f35721f0193c95ffb055d9e466e11\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3bafd2b0b2d28068d329f95ea8a1fbce3719c257fcb863fc01abcbafd8d531ab\",\"dweb:/ipfs/QmUeaFjKWTVDBsHVfSob4mwt6A5hTnKDz22HaUXeZhypa3\"]}},\"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":{"lib/forge-std/src/safeconsole.sol":"safeconsole"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/safeconsole.sol":{"keccak256":"0xbef9786cb49d3eade757bad87568c49c8c8f35721f0193c95ffb055d9e466e11","urls":["bzz-raw://3bafd2b0b2d28068d329f95ea8a1fbce3719c257fcb863fc01abcbafd8d531ab","dweb:/ipfs/QmUeaFjKWTVDBsHVfSob4mwt6A5hTnKDz22HaUXeZhypa3"],"license":"MIT"}},"version":1},"id":15} {"abi":[],"bytecode":{"object":"0x6080806040523460175760399081601c823930815050f35b5f80fdfe5f80fdfea2646970667358221220709c8134992b5fef4e2bf94b521207862a1126f22dcc0c41899199d76b8ca7c164736f6c634300081e0033","sourceMap":"163:427371:20:-:0;;;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x5f80fdfea2646970667358221220709c8134992b5fef4e2bf94b521207862a1126f22dcc0c41899199d76b8ca7c164736f6c634300081e0033","sourceMap":"163:427371:20:-:0;;","linkReferences":{}},"methodIdentifiers":{},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.30+commit.73712a01\"},\"language\":\"Solidity\",\"output\":{\"abi\":[],\"devdoc\":{\"author\":\"philogy <https://github.com/philogy>\",\"details\":\"Code generated automatically by script.\",\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"lib/forge-std/src/safeconsole.sol\":\"safeconsole\"},\"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/forge-std/src/safeconsole.sol\":{\"keccak256\":\"0xbef9786cb49d3eade757bad87568c49c8c8f35721f0193c95ffb055d9e466e11\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://3bafd2b0b2d28068d329f95ea8a1fbce3719c257fcb863fc01abcbafd8d531ab\",\"dweb:/ipfs/QmUeaFjKWTVDBsHVfSob4mwt6A5hTnKDz22HaUXeZhypa3\"]}},\"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":{"lib/forge-std/src/safeconsole.sol":"safeconsole"},"evmVersion":"prague","libraries":{},"viaIR":true},"sources":{"lib/forge-std/src/safeconsole.sol":{"keccak256":"0xbef9786cb49d3eade757bad87568c49c8c8f35721f0193c95ffb055d9e466e11","urls":["bzz-raw://3bafd2b0b2d28068d329f95ea8a1fbce3719c257fcb863fc01abcbafd8d531ab","dweb:/ipfs/QmUeaFjKWTVDBsHVfSob4mwt6A5hTnKDz22HaUXeZhypa3"],"license":"MIT"}},"version":1},"id":20}

View File

@@ -1,12 +1,12 @@
{ {
"11155111": { "11155111": {
"v1": { "v1": {
"PartyPlanner": "0x2954911231c44E49938b2FBd1e0cD2787FdF69AD", "PartyPlanner": "0x0ad06C08ab5049e6Fd4d7f5AF457115A1475326b",
"PartyPoolViewer": "0x71b04a353a77405a3217EAF3A24BA619B86cD5E9", "PartyPoolViewer": "0x750d63a39a4ccfCfB69D2f5aFDa065909C717cAB",
"PartyPoolMintImpl": "0x705272c50F905204187B3126701BeDEd82Dc2F9a", "PartyPoolMintImpl": "0x25bb10BA84944F8aAEf1fD247C3B7Fe7271C23F9",
"PartyPoolSwapImpl": "0xC9608aAaF772c1cAce83C863e88EC4FF54017CeB", "PartyPoolSwapImpl": "0x69b4F102e0747f61F8529b3bbFf2FC4b27438d0F",
"PartyPoolDeployer": "0x6811C56804321F811eAFa3f7694b026d738Ba7a1", "PartyPoolDeployer": "0x0939F93BAa3c96226853F9F39A95beF48eA8fF04",
"PartyPoolBalancedPairDeployer": "0xc321406Fc8e174Bb0D006C145D515b858b1b883d", "PartyPoolBalancedPairDeployer": "0xfda454fF7876aad9408517Ed2F0d11AA229Ad0a4",
"USXD": "0x8E4D16886b8946dfE463fA172129eaBf4825fb09", "USXD": "0x8E4D16886b8946dfE463fA172129eaBf4825fb09",
"FUSD": "0xdc225280216822CA956738390f589c794129bd53", "FUSD": "0xdc225280216822CA956738390f589c794129bd53",
"DIVE": "0x7ba123e4e7395A361284d069bD0D545F3f820641", "DIVE": "0x7ba123e4e7395A361284d069bD0D545F3f820641",

47
doc/introduction.md Normal file
View File

@@ -0,0 +1,47 @@
# Introduction
[Liquidity Party](https://liquidity.party) is a new game-theoretic multi-asset AMM based on this paper:
[Logarithmic Market Scoring Rules for Modular Combinatorial Information Aggregation](https://mason.gmu.edu/~rhanson/mktscore.pdf) (R. Hanson, 2002)
A Logarithmic Market Scoring Rule (LMSR) is a pricing formula for AMM's that know only their current asset inventories and no other information, naturally supporting multi-asset
Compared to Constant Product (CP) markets, LMSR offers:
1. Less slippage than CP for small and medium trade sizes
2. N-asset pools for trading long-tail pairs in a single hop
3. Lower fees (smaller spread)
## Deeper Liquidity
According to game theory, CP's slope at the current marginal price is too steep, overcharging takers with too much slippage at small and medium trade sizes. LMSR pools offer less slippage and cheaper liquidity for the small and medium trade sizes common for arbitrageurs and aggregators.
## Multi-asset
Naturally multi-asset, Liquidity Party altcoin pools provide direct, one-hop swaps on otherwise illiquid multi-hop pairs. Pools will quote any pair combination available in the pool:
| Assets | Pairs | Swap Gas | Mint Gas |
|-------:|------:|---------:|----------:|
| 2 | 1 | 131,000 | 143,000 |
| 2* | 1 | 118,000 | 143,000 |
| 10 | 45 | 142,000 | 412,000 |
| 20 | 190 | 157,000 | 749,000 |
| 50 | 1225 | 199,000 | 1,760,000 |
| 100 | 4950 | 269,000 | 2,684,000 |
\* Stablecoin pair pool optimization
Liquidity Party aggregates scarce, low market cap assets into a single pool, providing one-hop liquidity for exotic pairs without fragmenting LP assets. CP pools would need 190x the LP assets to provide the same pairwise liquidity as a single 20-asset Liquidity Party pool, due to asset fragmentation.
## Lower Fees
Since market makers offer the option to take either side of the market, they must receive a subsidy or charge a fee (spread) to compensate for adverse selection (impermanent loss). By protecting LP's against common value-extraction scenarios, LMSR pools have a reduced risk premium resulting in lower fees for takers.
### Minimized Impermanent Loss
### No Intra-Pool Arbitrage
LMSR
This leads to LP's of CP pools demanding higher fees than theoretically necessary. By minimizing impermanent loss for LP's, LMSR pools reduce the risk premium, providing lower fees and higher liquidity for takers.

View File

@@ -1,24 +0,0 @@
| Symbol | Address |
|-----------------|----------------------------------------------|
| **Stablecoins** | |
| USDT | `0xdAC17F958D2ee523a2206206994597C13D831ec7` |
| USDC | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` |
| USDe | `0x4c9EDD5852cd905f086C759E8383e09bff1E68B3` |
| DAI | `0x6B175474E89094C44Da98b954EedeAC495271d0F` |
| **Chain Coins** | |
| WETH | `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` |
| WBTC | `0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599` |
| WSOL | `0xd1D82d3Ab815E0B47e38EC2d666c5b8AA05Ae501` |
| BNB | `0xB8c77482e45F1F44dE1745F52C74426C631bDD52` |
| TRX | `0x50327c6c5a14DCaDE707ABad2E27eB517df87AB5` |
| POL | `0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6` |
| DOT | `0x21c2c96Dbfa137E23946143c71AC8330F9B44001` |
| NEAR | `0x85F17Cf997934a597031b2E18a9aB6ebD4B9f6a4` |
| **Others** | |
| WBETH | `0xa2E3356610840701BDf5611a53974510Ae27E2e1` |
| ARB | `0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1` |
| UNI | `0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984` |
| LINK | `0x514910771AF9Ca656af840dff83E8264EcF986CA` |
| AAVE | `0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9` |
| PEPE | `0x6982508145454Ce325dDbE47a25d4ec3d2311933` |
| SHIB | `0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE` |

View File

@@ -8,106 +8,78 @@ Multi-asset liquidity typically trades off simplicity and expressivity. Classica
## System Model and Pricing Kernel ## 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 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
$$ $$
C(\mathbf{q}) = b(\mathbf{q}) \log\!\left(\sum_{i=0}^{n-1} e^{q_i / b(\mathbf{q})}\right), \qquad b(\mathbf{q})=\kappa\,S(\mathbf{q}),\quad \kappa>0. C(\mathbf{q}) = b(\mathbf{q}) \log\!\left(\sum_{i=0}^{n-1} e^{q_i / b(\mathbf{q})}\right), \qquad b(\mathbf{q})=\kappa\,S(\mathbf{q}),\quad \kappa>0.
$$ $$
For numerical stability we evaluate $C$ with a log-sum-exp recentering. Let $y_i := q_i/b(\mathbf{q})$ and $M:=\max_i y_i$. Then For numerical stability we evaluate $C$ with a log-sum-exp recentering. Let $y_i := q_i/b(\mathbf{q})$ and $M:=\max_i y_i$. Then
$$ $$
C(\mathbf{q}) \;=\; b(\mathbf{q}) \left( M + \log \sum_{i=0}^{n-1} e^{\,y_i - M} \right), C(\mathbf{q}) \;=\; b(\mathbf{q}) \left( M + \log \sum_{i=0}^{n-1} e^{\,y_i - M} \right),
$$ $$
which prevents overflow/underflow when the $y_i$ are dispersed. Quantities are represented in fixed-point with explicit range and domain guards; equations are presented over the reals for clarity. which prevents overflow/underflow when the $y_i$ are dispersed. Quantities are represented in fixed-point with explicit range and domain guards; equations are presented over the reals for clarity.
## Gradient, Price Shares, and Pairwise Prices ## Gradient, Price Shares, and Pairwise Prices
With $b$ treated as a constant parameter, the LMSR gradient recovers softmax shares With $b$ treated as a constant parameter, the LMSR gradient recovers softmax shares
$$ $$
\frac{\partial C}{\partial q_i} \;=\; \frac{e^{q_i/b}}{\sum_k e^{q_k/b}} \;=:\; \pi_i(\mathbf{q}), \frac{\partial C}{\partial q_i} \;=\; \frac{e^{q_i/b}}{\sum_k e^{q_k/b}} \;=:\; \pi_i(\mathbf{q}),
$$ $$
so that the ratio of marginal prices is $\pi_j/\pi_i = \exp\!\big((q_j-q_i)/b\big)$. When $b(\mathbf{q})=\kappa S(\mathbf{q})$ depends on state, $\frac{\partial C}{\partial q_i}$ acquires a common additive term across $i$ from $\partial b/\partial q_i$, but pairwise ratios remain governed by softmax differences. We therefore use a quasi-static-$b$ view for pricing steps, holding $b$ fixed at the pre-trade state for the infinitesimal move, and define the instantaneous pairwise marginal price ratio for exchanging $i$ into $j$ as so that the ratio of marginal prices is $\pi_j/\pi_i = \exp\!\big((q_j-q_i)/b\big)$. When $b(\mathbf{q})=\kappa S(\mathbf{q})$ depends on state, $\frac{\partial C}{\partial q_i}$ acquires a common additive term across $i$ from $\partial b/\partial q_i$, but pairwise ratios remain governed by softmax differences. We therefore use a quasi-static-$b$ view for pricing steps, holding $b$ fixed at the pre-trade state for the infinitesimal move, and define the instantaneous pairwise marginal price ratio for exchanging $i$ into $j$ as
$$ $$
P(i\to j \mid \mathbf{q}) \;=\; \exp\!\left(\frac{q_j - q_i}{b(\mathbf{q})}\right). P(i\to j \mid \mathbf{q}) \;=\; \exp\!\left(\frac{q_j - q_i}{b(\mathbf{q})}\right).
$$ $$
This ratio drives swap computations and is invariant to proportional rescaling $\mathbf{q}\mapsto \lambda\mathbf{q}$ because $b$ scales by the same factor. This ratio drives swap computations and is invariant to proportional rescaling $\mathbf{q}\mapsto \lambda\mathbf{q}$ because $b$ scales by the same factor.
## Two-Asset Reduction and Exact Swap Mappings ## Two-Asset Reduction and Exact Swap Mappings
Swaps are computed in the two-asset subspace spanned by the in-asset $i$ and out-asset $j$, with all other coordinates held fixed under a quasi-static-$b$ step. Let Swaps are computed in the two-asset subspace spanned by the in-asset $i$ and out-asset $j$, with all other coordinates held fixed under a quasi-static-$b$ step. Let
$$ $$
r_0 \;:=\; \exp\!\left(\frac{q_i - q_j}{b}\right), \qquad b \equiv b(\mathbf{q})\;\text{ held quasi-static}. r_0 \;:=\; \exp\!\left(\frac{q_i - q_j}{b}\right), \qquad b \equiv b(\mathbf{q})\;\text{ held quasi-static}.
$$ $$
Along the $i\!\to\! j$ path, the instantaneous ratio evolves multiplicatively as $r(t)=r_0\,e^{t/b}$ where $t$ denotes cumulative input of asset $i$. In the two-asset reduction the infinitesimal output satisfies Along the $i\!\to\! j$ path, the instantaneous ratio evolves multiplicatively as $r(t)=r_0\,e^{t/b}$ where $t$ denotes cumulative input of asset $i$. In the two-asset reduction the infinitesimal output satisfies
$$ $$
\mathrm{d}y \;=\; \frac{r(t)}{1+r(t)}\,\mathrm{d}t. \mathrm{d}y \;=\; \frac{r(t)}{1+r(t)}\,\mathrm{d}t.
$$ $$
Integrating from $t=0$ to $t=a$ yields the exact-in closed form Integrating from $t=0$ to $t=a$ yields the exact-in closed form
$$ $$
y(a) \;=\; b \,\ln\!\Big( 1 + r_0 \,\big(1 - e^{-a/b}\big) \Big). y(a) \;=\; b \,\ln\!\Big( 1 + r_0 \,\big(1 - e^{-a/b}\big) \Big).
$$ $$
This mapping has $y(0)=0$, is strictly increasing and concave in $a$, and satisfies $y'(0)=\frac{r_0}{1+r_0}$ with asymptote $\lim_{a\to\infty} y = b\,\ln(1+r_0)$. The inverse exact-out mapping follows by solving for $a$ in terms of target $y$. Writing $E:=e^{y/b}$, we obtain This mapping has $y(0)=0$, is strictly increasing and concave in $a$, and satisfies $y'(0)=\frac{r_0}{1+r_0}$ with asymptote $\lim_{a\to\infty} y = b\,\ln(1+r_0)$. The inverse exact-out mapping follows by solving for $a$ in terms of target $y$. Writing $E:=e^{y/b}$, we obtain
$$ $$
a(y) \;=\; b \,\ln\!\left(\frac{r_0}{\,r_0 + 1 - E\,}\right), a(y) \;=\; b \,\ln\!\left(\frac{r_0}{\,r_0 + 1 - E\,}\right),
$$ $$
which is strictly increasing and convex for $y\in\big[0,\, b\ln(1+r_0)\big]$. These two expressions are the workhorses for exact-in and exact-out swaps in our kernel. which is strictly increasing and convex for $y\in\big[0,\, b\ln(1+r_0)\big]$. These two expressions are the workhorses for exact-in and exact-out swaps in our kernel.
## Price Limits, Swap-to-Limit, and Capacity Caps ## Price Limits, Swap-to-Limit, and Capacity Caps
Users may provide a maximum acceptable marginal price ratio $\Lambda>0$ for $p_i/p_j$. The marginal ratio trajectory $r(t)=r_0 e^{t/b}$ first reaches the limit at the unique Users may provide a maximum acceptable marginal price ratio $\Lambda>0$ for $p_i/p_j$. The marginal ratio trajectory $r(t)=r_0 e^{t/b}$ first reaches the limit at the unique
$$ $$
a_{\text{lim}} \;=\; b \,\ln\!\left(\frac{\Lambda}{r_0}\right), a_{\text{lim}} \;=\; b \,\ln\!\left(\frac{\Lambda}{r_0}\right),
$$ $$
and the output realized at that truncation is and the output realized at that truncation is
$$ $$
y_{\text{lim}} \;=\; b \,\ln\!\Big( 1 + r_0 \,\big(1 - r_0/\Lambda\big) \Big). y_{\text{lim}} \;=\; b \,\ln\!\Big( 1 + r_0 \,\big(1 - r_0/\Lambda\big) \Big).
$$ $$
Outputs are further bounded by available inventory; if a computed $y$ would exceed $q_j$, we cap at $y=q_j$ and compute the implied input by inverting the exact-out formula, Outputs are further bounded by available inventory; if a computed $y$ would exceed $q_j$, we cap at $y=q_j$ and compute the implied input by inverting the exact-out formula,
$$ $$
a_{\text{cap}} \;=\; b \,\ln\!\left(\frac{r_0}{\,r_0 + 1 - e^{\,q_j/b}\,}\right). a_{\text{cap}} \;=\; b \,\ln\!\left(\frac{r_0}{\,r_0 + 1 - e^{\,q_j/b}\,}\right).
$$ $$
These limit and capacity branches ensure monotone, conservative behavior near domain edges. These limit and capacity branches ensure monotone, conservative behavior near domain edges.
## Liquidity Operations from the Same Potential ## Liquidity Operations from the Same Potential
Liquidity is accounted via pool shares $L$ taken proportional to the size metric, and we set $L=S(\mathbf{q})$ without loss of generality. At initialization with seed balances $\mathbf{q}^{(0)}$ the pool sets $L^{(0)}=S^{(0)}$ and $b^{(0)}=\kappa S^{(0)}$. A proportional deposit that scales balances to $\mathbf{q}'=(1+\alpha)\mathbf{q}$ mints $\Delta L = \alpha S(\mathbf{q})$ shares and scales liquidity to $b'=(1+\alpha)b$. Single-asset deposits target a proportional growth while rebalancing through kernel swaps: providing amount $a$ of asset $i$ induces a growth factor $\alpha\ge 0$ satisfying the monotone equation Liquidity is accounted via pool shares $L$ taken proportional to the size metric, and we set $L=S(\mathbf{q})$ without loss of generality. At initialization with seed balances $\mathbf{q}^{(0)}$ the pool sets $L^{(0)}=S^{(0)}$ and $b^{(0)}=\kappa S^{(0)}$. A proportional deposit that scales balances to $\mathbf{q}'=(1+\alpha)\mathbf{q}$ mints $\Delta L = \alpha S(\mathbf{q})$ shares and scales liquidity to $b'=(1+\alpha)b$. Single-asset deposits target a proportional growth while rebalancing through kernel swaps: providing amount $a$ of asset $i$ induces a growth factor $\alpha\ge 0$ satisfying the monotone equation
$$ $$
a \;=\; a_{\text{req}}(\alpha) \;=\; \alpha q_i \;+\; \sum_{j\ne i} b \,\ln\!\left(\frac{r_{0,j}}{\,r_{0,j} + 1 - e^{\,\alpha q_j/b}\,}\right), \quad r_{0,j}:=\exp\!\left(\frac{q_i-q_j}{b}\right), a \;=\; a_{\text{req}}(\alpha) \;=\; \alpha q_i \;+\; \sum_{j\ne i} b \,\ln\!\left(\frac{r_{0,j}}{\,r_{0,j} + 1 - e^{\,\alpha q_j/b}\,}\right), \quad r_{0,j}:=\exp\!\left(\frac{q_i-q_j}{b}\right),
$$ $$
and mints $\Delta L=\alpha S(\mathbf{q})$ upon the unique solution. Proportional withdrawals burn $\Delta L$ and return $\alpha=\Delta L/S(\mathbf{q})$ of each asset, updating $b$ to $(1-\alpha)b$. Single-asset withdrawals redeem $\alpha q_i$ directly and swap each redeemed $\alpha q_j$ for $j\ne i$ into $i$ using the exact-in mapping evaluated on the local post-burn state; any capacity overrun is handled by a cap-and-invert branch as above. Because all operations reduce to the same two-asset closed forms, they inherit monotonicity and uniqueness. and mints $\Delta L=\alpha S(\mathbf{q})$ upon the unique solution. Proportional withdrawals burn $\Delta L$ and return $\alpha=\Delta L/S(\mathbf{q})$ of each asset, updating $b$ to $(1-\alpha)b$. Single-asset withdrawals redeem $\alpha q_i$ directly and swap each redeemed $\alpha q_j$ for $j\ne i$ into $i$ using the exact-in mapping evaluated on the local post-burn state; any capacity overrun is handled by a cap-and-invert branch as above. Because all operations reduce to the same two-asset closed forms, they inherit monotonicity and uniqueness.
### Single-Asset Mint and Redeem ### Single-Asset Mint and Redeem
#### Single-Asset Mint #### Single-Asset Mint
Given a deposit of amount $a>0$ of asset $i$, the pool targets a proportional growth factor $\alpha \ge 0$ so that the post-mint state can be rebalanced to $(1+\alpha)\,\mathbf{q}$ using fee-free kernel swaps from $i$ into each $j\ne i$. For each $j\ne i$, let $y_j := \alpha\,q_j$ and define $r_{0,j} := \exp\!\big((q_i - q_j)/b\big)$. The input required to realize $y_j$ via the exact-out inverse is Given a deposit of amount $a>0$ of asset $i$, the pool targets a proportional growth factor $\alpha \ge 0$ so that the post-mint state can be rebalanced to $(1+\alpha)\,\mathbf{q}$ using fee-free kernel swaps from $i$ into each $j\ne i$. For each $j\ne i$, let $y_j := \alpha\,q_j$ and define $r_{0,j} := \exp\!\big((q_i - q_j)/b\big)$. The input required to realize $y_j$ via the exact-out inverse is
$$ $$
x_j(\alpha) \;=\; b \,\ln\!\left(\frac{r_{0,j}}{\,r_{0,j} + 1 - e^{\,y_j/b}\,}\right), x_j(\alpha) \;=\; b \,\ln\!\left(\frac{r_{0,j}}{\,r_{0,j} + 1 - e^{\,y_j/b}\,}\right),
$$ $$
so the total required input for growth $\alpha$ is so the total required input for growth $\alpha$ is
$$ $$
a_{\text{req}}(\alpha) \;=\; \alpha\,q_i \;+\; \sum_{j\ne i} x_j(\alpha). a_{\text{req}}(\alpha) \;=\; \alpha\,q_i \;+\; \sum_{j\ne i} x_j(\alpha).
$$ $$
Properties and solver: Properties and solver:
- Monotonicity: $a_{\text{req}}(\alpha)$ is strictly increasing on its feasible domain, guaranteeing a unique solution. - Monotonicity: $a_{\text{req}}(\alpha)$ is strictly increasing on its feasible domain, guaranteeing a unique solution.
- Solver: bracket $\alpha$ (e.g., start from $\alpha\sim a/S$ and double until $a_{\text{req}}(\alpha)\ge a$ or a safety cap), then bisection to a small tolerance $\varepsilon$ (e.g., $\sim10^{-6}$ in fixed-point units). - Solver: bracket $\alpha$ (e.g., start from $\alpha\sim a/S$ and double until $a_{\text{req}}(\alpha)\ge a$ or a safety cap), then bisection to a small tolerance $\varepsilon$ (e.g., $\sim10^{-6}$ in fixed-point units).
@@ -119,36 +91,28 @@ Burning a proportional share $\alpha \in (0,1]$ returns a single asset $i$ by re
1) Form the local state after burn, $\mathbf{q}_{\text{local}}=(1-\alpha)\,\mathbf{q}$. 1) Form the local state after burn, $\mathbf{q}_{\text{local}}=(1-\alpha)\,\mathbf{q}$.
2) Start with the direct redemption $\alpha\,q_i$ in asset $i$. 2) Start with the direct redemption $\alpha\,q_i$ in asset $i$.
3) For each $j\ne i$, withdraw $a_j := \alpha\,q_j$ and swap $j\to i$ using the exact-in form evaluated at $\mathbf{q}_{\text{local}}$: 3) For each $j\ne i$, withdraw $a_j := \alpha\,q_j$ and swap $j\to i$ using the exact-in form evaluated at $\mathbf{q}_{\text{local}}$:
$$ $$
r_{0,j} \;=\; \exp\!\left(\frac{q^{\text{local}}_j - q^{\text{local}}_i}{b}\right),\qquad r_{0,j} \;=\; \exp\!\left(\frac{q^{\text{local}}_j - q^{\text{local}}_i}{b}\right),\qquad
y_{j\to i} \;=\; b \,\ln\!\Big(1 + r_{0,j}\,\big(1 - e^{-a_j/b}\big)\Big). y_{j\to i} \;=\; b \,\ln\!\Big(1 + r_{0,j}\,\big(1 - e^{-a_j/b}\big)\Big).
$$ $$
4) Capacity cap and inverse: if $y_{j\to i} > q^{\text{local}}_i$, cap to $y=q^{\text{local}}_i$ and solve the implied input via 4) Capacity cap and inverse: if $y_{j\to i} > q^{\text{local}}_i$, cap to $y=q^{\text{local}}_i$ and solve the implied input via
$$ $$
a_{j,\text{used}} \;=\; b \,\ln\!\left(\frac{r_{0,j}}{\,r_{0,j} + 1 - e^{\,q^{\text{local}}_i/b}\,}\right), a_{j,\text{used}} \;=\; b \,\ln\!\left(\frac{r_{0,j}}{\,r_{0,j} + 1 - e^{\,q^{\text{local}}_i/b}\,}\right),
$$ $$
then update $\mathbf{q}_{\text{local}}$ accordingly. then update $\mathbf{q}_{\text{local}}$ accordingly.
5) The single-asset payout is 5) The single-asset payout is
$$ $$
Y_i \;=\; \alpha\,q_i \;+\; \sum_{j\ne i} y_{j\to i}, \qquad \text{with LP burned } L_{\text{in}} = \alpha \, S(\mathbf{q}). Y_i \;=\; \alpha\,q_i \;+\; \sum_{j\ne i} y_{j\to i}, \qquad \text{with LP burned } L_{\text{in}} = \alpha \, S(\mathbf{q}).
$$ $$
Guards and behavior: Guards and behavior:
- Enforce $b>0$, positivity of inner terms (e.g., $r_{0,j} + 1 - e^{y/b} > 0$), and safe exponent ranges; treat any per-asset numerical failure as zero contribution rather than aborting the whole redeem. - Enforce $b>0$, positivity of inner terms (e.g., $r_{0,j} + 1 - e^{y/b} > 0$), and safe exponent ranges; treat any per-asset numerical failure as zero contribution rather than aborting the whole redeem.
- The mapping is monotone in $\alpha$; the cap-and-invert branch preserves safety near capacity. - The mapping is monotone in $\alpha$; the cap-and-invert branch preserves safety near capacity.
### LP Pricing vs. an Asset Token ### LP Pricing vs. an Asset Token
With LP supply set to $L=S(\mathbf{q})$, the instantaneous price of one LP share in units of asset $k$ aggregates marginal exchange rates from each asset into $k$: With LP supply set to $L=S(\mathbf{q})$, the instantaneous price of one LP share in units of asset $k$ aggregates marginal exchange rates from each asset into $k$:
$$ $$
P_L^{(k)}(\mathbf{q}) \;=\; \frac{1}{S(\mathbf{q})}\,\sum_{j=0}^{n-1} q_j \,\exp\!\left(\frac{q_j - q_k}{b(\mathbf{q})}\right). P_L^{(k)}(\mathbf{q}) \;=\; \frac{1}{S(\mathbf{q})}\,\sum_{j=0}^{n-1} q_j \,\exp\!\left(\frac{q_j - q_k}{b(\mathbf{q})}\right).
$$ $$
Interpretation: proportional deposits leave $P_L^{(k)}$ unchanged; swap fees retained in the pool increase $S$ relative to outstanding $L$, raising $P_L^{(k)}$ (implicit fee accrual). This expression helps LPs and integrators reason about share valuation and dilution across assets. Interpretation: proportional deposits leave $P_L^{(k)}$ unchanged; swap fees retained in the pool increase $S$ relative to outstanding $L$, raising $P_L^{(k)}$ (implicit fee accrual). This expression helps LPs and integrators reason about share valuation and dilution across assets.
## Numerical Methods and Safety Guarantees ## Numerical Methods and Safety Guarantees
@@ -156,17 +120,13 @@ We evaluate log-sum-exp with recentring, compute ratios like $r_0=\exp((q_i-q_j)
## Balanced Regime Optimization: Approximations, Dispatcher, and Stability ## Balanced Regime Optimization: Approximations, Dispatcher, and Stability
Since transcendental operations are gas-expensive on EVM chains, we use polynomial approximations in near-balanced regimes (e.g., stable-asset pairs) while preserving monotonicity and domain safety. Parameterize $\delta := (q_i - q_j)/b$ and $\tau := a/b$ for an $i\!\to\! j$ exact-in step. The exact mapping Since transcendental operations are gas-expensive on EVM chains, we use polynomial approximations in near-balanced regimes (e.g., stable-asset pairs) while preserving monotonicity and domain safety. Parameterize $\delta := (q_i - q_j)/b$ and $\tau := a/b$ for an $i\!\to\! j$ exact-in step. The exact mapping
$$ $$
y(a) \;=\; b \,\ln\!\Big(1 + e^{\delta}\,\big(1 - e^{-\tau}\big)\Big) y(a) \;=\; b \,\ln\!\Big(1 + e^{\delta}\,\big(1 - e^{-\tau}\big)\Big)
$$ $$
admits small-argument expansions for $|\delta|\ll 1$ and $|\tau|\ll 1$. Using $e^{\pm x}\approx 1\pm x+\tfrac{x^2}{2}$ and $\ln(1+u)\approx u - \tfrac{u^2}{2}$, we obtain admits small-argument expansions for $|\delta|\ll 1$ and $|\tau|\ll 1$. Using $e^{\pm x}\approx 1\pm x+\tfrac{x^2}{2}$ and $\ln(1+u)\approx u - \tfrac{u^2}{2}$, we obtain
$$ $$
y(a) \;\approx\; b \left[ r_0 \tau - \tfrac{1}{2} r_0 \tau^2 \right] + \mathcal{O}\!\left(\tau^3,\, |\delta|\,\tau^2\right), \qquad r_0=e^{\delta}\approx 1+\delta+\tfrac{\delta^2}{2}, y(a) \;\approx\; b \left[ r_0 \tau - \tfrac{1}{2} r_0 \tau^2 \right] + \mathcal{O}\!\left(\tau^3,\, |\delta|\,\tau^2\right), \qquad r_0=e^{\delta}\approx 1+\delta+\tfrac{\delta^2}{2},
$$ $$
and at $\delta=0$ the symmetry reduces to $y(a)\approx \tfrac{a}{2} - \tfrac{a^2}{4b} + \cdots$. and at $\delta=0$ the symmetry reduces to $y(a)\approx \tfrac{a}{2} - \tfrac{a^2}{4b} + \cdots$.
### Dispatcher preconditions and thresholds (approx path): ### Dispatcher preconditions and thresholds (approx path):
@@ -191,63 +151,20 @@ and at $\delta=0$ the symmetry reduces to $y(a)\approx \tfrac{a}{2} - \tfrac{a^2
- Regardless of path, our policy prioritizes monotonicity, domain safety, and conservative decisions at boundaries. - Regardless of path, our policy prioritizes monotonicity, domain safety, and conservative decisions at boundaries.
## Fees and Economic Considerations ## Fees and Economic Considerations
Fees are applied outside the fee-free LMSR kernel and are retained in the pool so that fee accrual increases the size metric $S(\mathbf{q})$ (and thereby raises LP share value under $L\propto S$). We extend the single global swap-fee to a per-token fee vector $f = (f_0, f_1, \dots, f_{n-1})$, where $f_i$ denotes the canonical fee rate associated with token $i$ (expressed as a fractional rate, e.g., ppm or bps). For a trade that takes token $i$ as input and token $j$ as output, the pool computes an effective pair fee and applies it to the user-submitted input before invoking the fee-free kernel. Swap fees are applied outside the fee-free kernel. For an exact-in submission $a$ on asset $i$, the effective kernel input is $a_{\text{eff}}=(1-f_{\text{swap}})a$. The kernel computes output using $a_{\text{eff}}$, while the retained fee remains in the pool, increasing $S(\mathbf{q})$ relative to outstanding $L$ and thereby accruing value to LPs implicitly. Scale invariance under $b=\kappa S$ implies that proportional growth of inventories preserves price ratios while deepening notional liquidity linearly. The classical LMSR bounded-loss intuition for constant $b$ gives $b\ln n$ in appropriate units; under our proportional $b$, this scales with $S$, so the instantaneous bound per unit of $S$ is proportional to $\kappa\ln n$.
Effective pair fee composition
- The effective fee for an asset-to-asset swap is an exact multiplicative composition:
$$
f_{\mathrm{eff}} \;=\; 1 - (1 - f_i)\,(1 - f_j),
$$
Asset-to-asset policy
- Charge on input: compute the kernel input as
$$
a_{\mathrm{eff}} \;=\; a_{\mathrm{user}}\,(1 - f_{\mathrm{eff}})
$$
and pass $a_{\mathrm{eff}}$ to the fee-free LMSR kernel; collect the retained fee in the input token. Charging on input keeps gas logic simple and makes effective price shifts monotone and predictable for takers.
- Protocol fees are taken as a fraction of LP fee earnings, and immediately moved to a separate account that does not participate in liquidity operations.
- Limit semantics: all limitPrice and cap computations refer to the fee-free kernel path (i.e., are evaluated against the kernel output computed from $a_{\mathrm{eff}}$). Aggregators should compute $f_{\mathrm{eff}}$ externally and present accurate expected outputs to users.
SwapMint and BurnSwap: single-asset fee policy
- Overview: swapMint (single-asset mint) and burnSwap (single-asset redeem) are single-asset-facing operations that interface the pool with one external token and the LP shares on the other side. To keep semantics simple and predictable, only the single assets fee is applied for these operations; there is no separate “LP token” fee ($f_{\mathrm{LP}} = 0$).
- swapMint (deposit one token to mint LP):
- Apply only the deposited tokens fee $f_i$. Compute the effective kernel input as
$$
a_{\mathrm{eff}} \;=\; a_{\mathrm{user}}\,(1 - f_i).
$$
The fee is collected in the deposited token and split by the protocol share $\phi$; the remainder increases the pool (raising $S$ and accruing value to LPs implicitly).
- burnSwap (burn LP to receive one token):
- Apply only the withdrawn tokens fee $f_j$. Compute the gross payout via the fee-free kernel for the burned LP fraction, and remit to the user:
$$
\text{payout}_{\mathrm{net}} \;=\; \text{payout}_{\mathrm{gross}}\,(1 - f_j).
$$
The collected fee is retained in the withdrawn token, the protocol takes $\phi$ of that fee, and the remainder increases pool-held balances (raising $S$ for remaining LPs).
Rationale and interactions with pair-fee rules
- Conceptual consistency: single-asset operations touch a single external token, so applying only that tokens fee is the most natural mapping from the per-token fee vector to operation-level economics. For asset-to-asset swaps the two-token multiplicative composition remains the canonical rule.
- $f_{\mathrm{LP}} = 0$: keeping LP-side fees at zero simplifies LP accounting and avoids double charging when LP shares are the other leg of a transaction. LPs still receive value via retained fees that increase $S$.
Rounding
Our policies aim to always protect the LPs value.
- Total fees are rounded up for the benefit of the pool and against takers.
- The Protocol fee is rounded down for the benefit of LPs and against the protocol developers.
## Risk Management and Bounded Loss ## Risk Management and Bounded Loss
Under constant $b$, classical LMSR admits a worst-case loss bound of $b \ln n$ in the payoff numéraire. With $b(\mathbf{q})=\kappa S(\mathbf{q})$, the per-state bound scales with the current size metric, giving an instantaneous worst-case loss $b(\mathbf{q}) \ln n = \kappa\,S(\mathbf{q})\,\ln n$; per unit of size $S$ this is $\kappa \ln n$. Because $b$ varies with state, global worst-case loss along an arbitrary path depends on how $S$ evolves, but the proportionality clarifies how risk scales with liquidity. Operational mitigations include user price limits (swap-to-limit), capacity caps on outputs ($y \le q_j$), minimum bootstrap $S^{(0)}$ to avoid thin-liquidity regimes, and strict numerical guards (e.g., positivity of inner logarithm arguments) to prevent nonphysical states. Under constant $b$, classical LMSR admits a worst-case loss bound of $b \ln n$ in the payoff numéraire. With $b(\mathbf{q})=\kappa S(\mathbf{q})$, the per-state bound scales with the current size metric, giving an instantaneous worst-case loss $b(\mathbf{q}) \ln n = \kappa\,S(\mathbf{q})\,\ln n$; per unit of size $S$ this is $\kappa \ln n$. Because $b$ varies with state, global worst-case loss along an arbitrary path depends on how $S$ evolves, but the proportionality clarifies how risk scales with liquidity. Operational mitigations include user price limits (swap-to-limit), capacity caps on outputs ($y \le q_j$), minimum bootstrap $S^{(0)}$ to avoid thin-liquidity regimes, and strict numerical guards (e.g., positivity of inner logarithm arguments) to prevent nonphysical states.
## Deployment and Parameter Fixity ## Deployment and Parameter Fixity
The parameter tuple $(\kappa, f_{\text{swap}}, \phi)$ is set at deployment and remains immutable, with $\kappa>0$ defining $b(\mathbf{q})=\kappa S(\mathbf{q})$, $f_{\text{swap}}$ the swap fee rate, and $\phi$ the protocol share of fees. Given the initial state $\mathbf{q}^{(0)}$ with $S^{(0)}>0$, the induced pricing map is fully determined by The parameter tuple $(\kappa, f_{\text{swap}}, \phi)$ is set at deployment and remains immutable, with $\kappa>0$ defining $b(\mathbf{q})=\kappa S(\mathbf{q})$, $f_{\text{swap}}$ the swap fee rate, and $\phi$ the protocol share of fees. Given the initial state $\mathbf{q}^{(0)}$ with $S^{(0)}>0$, the induced pricing map is fully determined by
$$ $$
C(\mathbf{q}) = b(\mathbf{q}) \log\!\left(\sum_i e^{q_i / b(\mathbf{q})}\right), \qquad b(\mathbf{q})=\kappa S(\mathbf{q}), C(\mathbf{q}) = b(\mathbf{q}) \log\!\left(\sum_i e^{q_i / b(\mathbf{q})}\right), \qquad b(\mathbf{q})=\kappa S(\mathbf{q}),
$$ $$
and the two-asset closed forms above. Fixity eliminates governance risk, makes depth calibration transparent, and simplifies integration for external routers and valuation tools. and the two-asset closed forms above. Fixity eliminates governance risk, makes depth calibration transparent, and simplifies integration for external routers and valuation tools.
## Conclusion ## Conclusion
By coupling LMSR with the proportional parameterization $b(\mathbf{q})=\kappa S(\mathbf{q})$, we obtain a multi-asset AMM that preserves softmax-driven price ratios under a quasi-static-b view and supports any-to-any swaps via a single convex potential. Exact two-asset reductions yield closed-form mappings for exact-in, exact-out, limit-hitting, and capped-output trades, and the same formulas underpin liquidity operations with monotonicity and uniqueness. Numerical stability follows from log-sum-exp evaluation, ratio-first derivations, guarded transcendental domains, and optional near-balance approximations, while fixed parameters provide predictable scaling and transparent economics. By coupling LMSR with the proportional parameterization $b(\mathbf{q})=\kappa S(\mathbf{q})$, we obtain a multi-asset AMM that preserves softmax-driven price ratios under a quasi-static-$b$ view and supports any-to-any swaps via a single convex potential. Exact two-asset reductions yield closed-form mappings for exact-in, exact-out, limit-hitting, and capped-output trades, and the same formulas underpin liquidity operations with monotonicity and uniqueness. Numerical stability follows from log-sum-exp evaluation, ratio-first derivations, guarded transcendental domains, and optional near-balance approximations, while fixed parameters provide predictable scaling and transparent economics.
## References ## References
Hanson, R. (2002) [_Logarithmic Market Scoring Rules for Modular Combinatorial Information Aggregation_](https://mason.gmu.edu/~rhanson/mktscore.pdf) Hanson, R. (2002) [_Logarithmic Market Scoring Rules for Modular Combinatorial Information Aggregation_](https://mason.gmu.edu/~rhanson/mktscore.pdf)
Othman, Pennock, Reeves, Sandholm (2013) [_A Practical Liquidity-Sensitive Automated Market Maker_](https://www.cs.cmu.edu/~sandholm/liquidity-sensitive%20automated%20market%20maker.teac.pdf)
Xu, Paruch, Cousaert, Feng (2023) [SoK: Decentralized Exchanges (DEX) with Automated Market Maker (AMM) Protocols](https://arxiv.org/pdf/2103.12732)

View File

@@ -1,171 +0,0 @@
import logging
import math
from itertools import combinations
log = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
# Now interpret the `weights` mapping as the desired pair fee (in bps) vs USDC.
# Examples:
# - USDC: 0.0 -> trading USDC<>USDC costs 0 bps
# - USDT: 0.10 -> trading USDT<>USDC costs ~0.1 bps
# - WIF: 30.0 -> trading WIF<>USDC costs ~30 bps
#
# For arbitrary pair A<>B we compose per-asset fees multiplicatively:
# f_eff = 1 - (1 - f_A) * (1 - f_B)
# which is ≈ f_A + f_B for small fees.
STABLECOIN_RATE = 0.01 # bps
X0 = STABLECOIN_RATE / 2
targets = {
'USDT': STABLECOIN_RATE,
'USDC': STABLECOIN_RATE,
'WBTC': 3.0, # ~3 bps vs USDC
'WETH': 5.0, # ~5 bps vs USDC
'WIF': 30.0, # ~30 bps vs USDC
}
weights = {k:v-X0 for k,v in targets.items()}
# UI / safety parameters (bps)
# cap_pair_fee_bps: global cap on the composed pair fee to avoid degenerate values (set to None to disable)
cap_pair_fee_bps = None # safety cap (bps); adjust or set to None to disable
# Compute geometric mean "base" of weights (kept for diagnostics)
def geometric_mean(vals):
# Guard: all weights must be positive (allow zero for USDC)
for v in vals:
if v < 0:
raise ValueError("All weights must be non-negative")
# exclude zeros when computing geometric mean to avoid exact zero product
pos_vals = [v for v in vals if v > 0]
if not pos_vals:
return 0.0
return math.prod(pos_vals) ** (1.0 / len(pos_vals))
base = geometric_mean(list(weights.values()))
ref_asset = 'USDC'
# Convert UI bps -> fractional form for internal calculations
def bps_to_frac(bps_val):
return bps_val / 10_000.0
log.info(
f"Fee model (weights are target bps vs USDC): ref_asset={ref_asset}, base_geo={base:.6f}"
)
def clamp_nonneg(x):
return x if x >= 0.0 else 0.0
def clamp_cap_frac(x_frac):
"""Clamp a fractional fee to configured cap_pair_fee_bps if set"""
if cap_pair_fee_bps is None:
return x_frac
cap_frac = bps_to_frac(cap_pair_fee_bps)
return min(x_frac, cap_frac)
def per_asset_fee(w_bps):
"""
Interpret `w_bps` directly as the target bps vs USDC for that asset and
return the fractional per-asset fee (clamped).
So for asset A:
f_A = bps_to_frac(weights[A])
"""
return clamp_nonneg(bps_to_frac(w_bps))
def fee_for_pair(w_in_bps, w_out_bps):
"""
Compute effective fee fraction for a swap i->j using multiplicative composition
of per-asset fees:
f_i = per_asset_fee(w_in_bps)
f_j = per_asset_fee(w_out_bps)
f_eff = 1 - (1 - f_i) * (1 - f_j)
Returns tuple (f_eff_frac, f_i_frac, f_j_frac).
"""
f_i = per_asset_fee(w_in_bps)
f_j = per_asset_fee(w_out_bps)
# multiplicative composition (accurate and gas-cheap counterpart)
f_eff = 1.0 - (1.0 - f_i) * (1.0 - f_j)
# apply global cap if configured
f_eff = clamp_cap_frac(f_eff)
return clamp_nonneg(f_eff), f_i, f_j
def pct(x):
return f"{100.0 * x:.6f}%"
def bps(x):
# x expected as fraction; convert to bps (1 bps = 1/10000)
return f"{10_000.0 * x:.4f} bps"
if __name__ == "__main__":
names = list(weights.keys())
vals = list(weights.values())
# Warn if any single-asset implied fee would produce large numbers
alert_threshold_bps = 1000.0
alerts = []
max_w = max(weights.values())
min_w = min(weights.values())
max_diff = max_w - min_w
if max_w > alert_threshold_bps:
alerts.append(("single_asset_too_large_bps", max_w))
if alerts:
log.warning("Some fee configuration may produce large values (bps): %s", alerts)
# Per-asset diagnostic: show per-asset fee (interpreted vs USDC)
for n, w in weights.items():
f_token = per_asset_fee(w)
print(f"{n:>12} {bps(f_token):>12}")
print()
for (name_a, w_a), (name_b, w_b) in combinations(weights.items(), 2):
f_eff_ab, f_i_ab, f_j_ab = fee_for_pair(w_a, w_b)
print(
f"{name_a+'-'+name_b:>12} {bps(f_eff_ab):>12}"
)
# -- Solidity (ABDK Q64.64) output --
# Print derived per-asset fees and cap as Solidity int128 Q64.64 constants that can be pasted
# into a Solidity file using ABDK's 64.64 fixed-point representation (int128 constants).
print("\n// Solidity (ABDK Q64.64) constants - generated by research/fees.py")
print("// Per-asset fees (FEE_<SYMBOL>) are Q64.64 int128 literals representing the fractional fee")
print("// Example: int128 internal constant FEE_USDT = 0x012345...; // comment\n")
# Helper: order tokens consistently for array examples
token_names = list(weights.keys())
for name in token_names:
w_bps = weights[name]
t_bps = targets[name]
f_frac = per_asset_fee(w_bps)
q64_int = int(round(f_frac * (1 << 64)))
hexstr = hex(q64_int)
print(f"int128 internal constant FEE_{name} = {hexstr}; // {bps(f_frac)}")
# Cap constant if configured
if cap_pair_fee_bps is not None:
cap_frac = bps_to_frac(cap_pair_fee_bps)
cap_q64 = int(round(cap_frac * (1 << 64)))
print(f"int128 internal constant CAP_PAIR_FEE_Q64 = {hex(cap_q64)}; // cap {cap_pair_fee_bps} bps")
# Example how to assemble into an array in the same order as `token_names`.
print("\n// Example: build a per-asset fee array (same ordering as token_names list above)")
print(f"// token order: {token_names}")
print(f"int128[] memory perAssetFeesQ64 = new int128[]({len(token_names)});")
for idx, name in enumerate(token_names):
print(f"perAssetFeesQ64[{idx}] = FEE_{name};")
print("\n// End of generated Solidity constants\n")
# Notes:
# - weights[name] should be set to the desired bps (not fraction) vs USDC.
# - Per-asset fraction f_token = bps_to_frac(weights[name]) and
# composed pair fee is f_eff = 1 - (1 - f_i) * (1 - f_j).
# - This keeps USDC as the reference (weights['USDC'] == 0.0).

View File

@@ -7,6 +7,7 @@ import numpy as np
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
LMSR_FEE = 0.0025
# UNISWAP_GAS=0 # UNISWAP_GAS=0
# LMSR_GAS=0 # LMSR_GAS=0
UNISWAP_GAS=115_000 UNISWAP_GAS=115_000
@@ -179,66 +180,31 @@ def lmsr_marginal_price(balances, base_index, quote_index, kappa):
def compare(file, tvl, fee, kappa): def compare(file, tvl, kappa):
d = pd.read_csv(file) d = pd.read_csv(file)
d.columns = ['block', 'price0', 'price1', 'in0', 'out0', 'rate'] d.columns = ['block', 'price0', 'price1', 'in0', 'out0', 'rate']
# New approach: derive bases from initial external balances (assuming equal-valued deposits) # Calibrate LMSR balances so that exp((q1 - q0)/b) equals the initial price
# This matches the Solidity implementation and eliminates the κ·ln(price) constraint
p0 = float(d.iloc[0].price0) p0 = float(d.iloc[0].price0)
S = float(tvl) # choose the LMSR size metric
# Set external balances assuming equal values: if token0 = B0 and token1 = B1, b = kappa * S
# and they have equal value, then B0 * price0 = B1 * price1 = V (value per asset) delta = b * math.log(p0) # q1 - q0
# For simplicity, choose B0 such that the total value is tvl, then B1 = B0 * price0 q0 = 0.5 * (S - delta)
total_value = float(tvl) q1 = 0.5 * (S + delta)
# Since B0 * price0 + B1 = total_value and B1 = B0 * price0, we get: if q0 <= 0.0 or q1 <= 0.0:
# B0 * price0 + B0 * price0 = total_value, so B0 = total_value / (2 * price0) raise ValueError("Invalid LMSR calibration: choose kappa such that kappa * ln(price0) < 1.")
B0 = total_value / (2.0 * p0) # external balance of token 0
B1 = B0 * p0 # external balance of token 1 (equal value)
external_balances = [B0, B1]
# Derive bases: set base_i = B_i so that q_i = B_i / base_i = 1.0 internally
bases = [B0, B1]
# Internal balances: q_i = external_balance_i / base_i ≈ 1.0
q0 = B0 / bases[0] # ≈ 1.0
q1 = B1 / bases[1] # ≈ 1.0
balances = [q0, q1] balances = [q0, q1]
print(f"External balances: {external_balances}") print(balances)
print(f"Bases: {bases}")
print(f"Internal balances: {balances}")
# Convert external input amounts to internal for LMSR calculations, then convert results back
X = np.geomspace(1, 1_000_000, 100) X = np.geomspace(1, 1_000_000, 100)
orig_price = lmsr_marginal_price(balances, 0, 1, kappa) orig_price = lmsr_marginal_price(balances, 0, 1, kappa)
in_out = [(float(amount_in), lmsr_swap_amount_out(balances, float(amount_in), 0, 1, LMSR_FEE, kappa)) for amount_in in X]
# Convert X to internal amounts, compute swap, then convert back to external print(in_out)
in_out = []
for amount_in_external in X:
# Convert external input to internal units
amount_in_internal = amount_in_external / bases[0] # input token 0
# Compute swap in internal units
amount_out_internal = lmsr_swap_amount_out(balances, amount_in_internal, 0, 1, fee, kappa)
# Convert output back to external units
amount_out_external = amount_out_internal * bases[1] # output token 1
in_out.append((float(amount_in_external), float(amount_out_external)))
print(f"Sample internal/external conversions: {in_out[:3]}")
# Compute initial marginal price in external units
# Internal price is exp((q1 - q0)/b), external price needs conversion by bases[1]/bases[0]
orig_price_external = orig_price * (bases[1] / bases[0])
# Relative execution price deviation from the initial marginal price: # Relative execution price deviation from the initial marginal price:
# slippage = |(amount_out/amount_in)/orig_price_external - 1| # slippage = |(amount_out/amount_in)/orig_price - 1|
eps = 1e-12 eps = 1e-12
Y = [max(eps, abs((amount_out / amount_in) / orig_price_external - 1.0)) Y = [max(eps, abs((amount_out / amount_in) / orig_price - 1.0))
for amount_in, amount_out in in_out] for amount_in, amount_out in in_out]
plt.plot(X, Y, label=f'LMSR {fee:.2%} κ={kappa:.2g}', color='cornflowerblue') plt.plot(X, Y, label=f'LMSR {LMSR_FEE:.2%} κ={kappa:.2f}', color='cornflowerblue')
# Uniswap execution price deviation from its initial quoted price: # Uniswap execution price deviation from its initial quoted price:
# slippage = |(out/in)/initial_price - 1| # slippage = |(out/in)/initial_price - 1|
@@ -291,6 +257,6 @@ def plot_kappa():
if __name__ == '__main__': if __name__ == '__main__':
# compare('uni4_quotes/swap_results_block_23640998.csv') # compare('uni4_quotes/swap_results_block_23640998.csv')
compare('uni4_quotes/ETH-USDC-30.csv', 53_000_000, 0.0025, 0.00025) # compare('uni4_quotes/ETH-USDC-30.csv', 53_000_000, 0.1)
# compare('uni4_quotes/ETH-USDC-30.csv', 100_000, 0.0025, 0.00025) compare('uni4_quotes/ETH-USDC-30.csv', 1_00_000, .1)
# plot_kappa() # plot_kappa()

View File

@@ -2,9 +2,7 @@ import { ethers } from 'ethers';
import { Token } from '@uniswap/sdk-core'; import { Token } from '@uniswap/sdk-core';
import fs from 'fs'; import fs from 'fs';
// // Token definitions
// TOKEN DEFINITIONS
//
const ChainId = { const ChainId = {
MAINNET: 1 MAINNET: 1
}; };
@@ -33,18 +31,11 @@ const USDT_TOKEN= new Token(
'USDT' 'USDT'
); );
//
// POOL DEFINITION
//
const tokenA = USDC_TOKEN const tokenA = USDC_TOKEN
const tokenB = WETH_TOKEN const tokenB = WETH_TOKEN
// Pool ID to fetch pool key from // Pool ID to fetch pool key from
// const POOL_ID = '0x8aa4e11cbdf30eedc92100f4c8a31ff748e201d44712cc8c90d189edaa8e4e47'; // USDT-USDC 0.0010% // const POOL_ID = '0x8aa4e11cbdf30eedc92100f4c8a31ff748e201d44712cc8c90d189edaa8e4e47';
// const POOL_ID = '0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d'; // USDC-WETH 0.30% const POOL_ID = '0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d';
const POOL_ID = '0xdce6394339af00981949f5f3baf27e3610c76326a700af57e4b3e3ae4977f78d'; // USDC-WETH 0.05%
// Configuration // Configuration
const QUOTER_ADDRESS = '0x52f0e24d1c21c8a0cb1e5a5dd6198556bd9e1203'; const QUOTER_ADDRESS = '0x52f0e24d1c21c8a0cb1e5a5dd6198556bd9e1203';

View File

@@ -11,7 +11,7 @@ import {StdUtils} from "../lib/forge-std/src/StdUtils.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IERC20Metadata} from "../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {PartyPlanner} from "../src/PartyPlanner.sol"; import {PartyPlanner} from "../src/PartyPlanner.sol";
import {PartyInfo} from "../src/PartyInfo.sol"; import {PartyPoolViewer} from "../src/PartyPoolViewer.sol";
import {Deploy} from "../test/Deploy.sol"; import {Deploy} from "../test/Deploy.sol";
import {MockERC20} from "../test/MockERC20.sol"; import {MockERC20} from "../test/MockERC20.sol";
@@ -67,6 +67,7 @@ contract DeployMock is Script {
'Token Pool', 'Token Pool',
'TP', 'TP',
tokens, tokens,
_bases,
ABDKMath64x64.divu(1, 10), ABDKMath64x64.divu(1, 10),
ABDKMath64x64.divu(1,10000), ABDKMath64x64.divu(1,10000),
_feePpm, _feePpm,
@@ -75,7 +76,7 @@ contract DeployMock is Script {
msg.sender, // payer: this script msg.sender, // payer: this script
DEV_ACCOUNT_7, // receiver of initial LP DEV_ACCOUNT_7, // receiver of initial LP
initialDeposits, initialDeposits,
10_000 * 10*18, 10000,
0 0
); );
@@ -111,6 +112,7 @@ contract DeployMock is Script {
'Stablecoin Pool', 'Stablecoin Pool',
'STAP', 'STAP',
IERC20[](tokens), IERC20[](tokens),
_bases,
ABDKMath64x64.divu(1, 10), ABDKMath64x64.divu(1, 10),
ABDKMath64x64.divu(1,10000), ABDKMath64x64.divu(1,10000),
_feePpm, _feePpm,
@@ -119,7 +121,7 @@ contract DeployMock is Script {
msg.sender, // payer: this script msg.sender, // payer: this script
DEV_ACCOUNT_7, // receiver of initial LP DEV_ACCOUNT_7, // receiver of initial LP
initialDeposits, initialDeposits,
10_000 * 10*18, 10000,
0 0
); );
@@ -152,6 +154,7 @@ contract DeployMock is Script {
'Stable Pair', 'Stable Pair',
'SPAIR', 'SPAIR',
IERC20[](tokens), IERC20[](tokens),
_bases,
ABDKMath64x64.divu(8,10), // kappa = 0.8 ABDKMath64x64.divu(8,10), // kappa = 0.8
_feePpm, _feePpm,
_feePpm, _feePpm,
@@ -159,11 +162,11 @@ contract DeployMock is Script {
msg.sender, // payer: this script msg.sender, // payer: this script
DEV_ACCOUNT_7, // receiver of initial LP DEV_ACCOUNT_7, // receiver of initial LP
initialDeposits, initialDeposits,
10_000 * 10*18, 10000,
0 0
); );
PartyInfo info = Deploy.newInfo(); PartyPoolViewer viewer = Deploy.newViewer();
// give _tokens to dev7 for later use // give _tokens to dev7 for later use
mintAll(DEV_ACCOUNT_7, 1_000_000); mintAll(DEV_ACCOUNT_7, 1_000_000);
@@ -172,9 +175,9 @@ contract DeployMock is Script {
// Set ENV vars // Set ENV vars
string memory plannerStr = vm.toString(address(planner)); string memory plannerStr = vm.toString(address(planner));
string memory infoStr = vm.toString(address(info)); string memory viewerStr = vm.toString(address(viewer));
vm.setEnv('PLANNER', plannerStr); vm.setEnv('PLANNER', plannerStr);
vm.setEnv('INFO', infoStr); vm.setEnv('VIEWER', viewerStr);
vm.setEnv('USXD', vm.toString(address(usxd))); vm.setEnv('USXD', vm.toString(address(usxd)));
vm.setEnv('FUSD', vm.toString(address(fusd))); vm.setEnv('FUSD', vm.toString(address(fusd)));
vm.setEnv('DIVE', vm.toString(address(dive))); vm.setEnv('DIVE', vm.toString(address(dive)));
@@ -183,14 +186,14 @@ contract DeployMock is Script {
// Write JSON config file // Write JSON config file
string memory chainConfigStr = vm.serializeString('config', 'PartyPlanner', plannerStr); string memory chainConfigStr = vm.serializeString('config', 'PartyPlanner', plannerStr);
chainConfigStr = vm.serializeString('config', 'PartyInfo', infoStr); chainConfigStr = vm.serializeString('config', 'PartyPoolViewer', viewerStr);
string memory v1ConfigStr = vm.serializeString('v1', 'v1', chainConfigStr); string memory v1ConfigStr = vm.serializeString('v1', 'v1', chainConfigStr);
string memory configStr = vm.serializeString('chain config', vm.toString(block.chainid), v1ConfigStr); string memory configStr = vm.serializeString('chain config', vm.toString(block.chainid), v1ConfigStr);
vm.writeJson(configStr, 'liqp-deployments.json'); vm.writeJson(configStr, 'liqp-deployments.json');
console2.log(); console2.log();
console2.log('PartyPlanner', address(planner)); console2.log(' PartyPlanner', address(planner));
console2.log(' PartyInfo', address(info)); console2.log('PartyPoolViewer', address(viewer));
console2.log(' USXD', address(usxd)); console2.log(' USXD', address(usxd));
console2.log(' FUSD', address(fusd)); console2.log(' FUSD', address(fusd));
console2.log(' DIVE', address(dive)); console2.log(' DIVE', address(dive));

View File

@@ -1,26 +1,14 @@
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30; pragma solidity ^0.8.30;
import "../test/Deploy.sol";
import "../src/IPartyPool.sol";
import "../src/PartyPlanner.sol";
import "../src/PartyPool.sol";
import "../test/MockERC20.sol";
import "@abdk/ABDKMath64x64.sol";
import "forge-std/Script.sol";
import "forge-std/console2.sol"; import "forge-std/console2.sol";
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
import {CommonBase} from "../lib/forge-std/src/Base.sol";
import {Script} from "../lib/forge-std/src/Script.sol";
import {StdChains} from "../lib/forge-std/src/StdChains.sol";
import {StdCheatsSafe} from "../lib/forge-std/src/StdCheats.sol";
import {StdUtils} from "../lib/forge-std/src/StdUtils.sol";
import {IERC3156FlashBorrower} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IPartyPool} from "../src/IPartyPool.sol";
import {IPartyInfo} from "../src/IPartyInfo.sol";
import {LMSRStabilized} from "../src/LMSRStabilized.sol";
import {NativeWrapper} from "../src/NativeWrapper.sol";
import {PartyPlanner} from "../src/PartyPlanner.sol";
import {PartyPoolDeployer, PartyPoolBalancedPairDeployer} from "../src/PartyPoolDeployer.sol";
import {PartyPoolMintImpl} from "../src/PartyPoolMintImpl.sol";
import {PartyPoolSwapImpl} from "../src/PartyPoolSwapImpl.sol";
import {PartyInfo} from "../src/PartyInfo.sol";
import {MockERC20} from "../test/MockERC20.sol";
import {MockFlashBorrower} from "../test/MockFlashBorrower.sol";
contract DeploySepolia is Script { contract DeploySepolia is Script {
@@ -34,24 +22,11 @@ contract DeploySepolia is Script {
vm.startBroadcast(); vm.startBroadcast();
// create mock _tokens // create mock _tokens
// usxd = new MockERC20('Joke Currency', 'USXD', 6); usxd = new MockERC20('Joke Currency', 'USXD', 6);
// fusd = new MockERC20('Fake USD', 'FUSD', 6); fusd = new MockERC20('Fake USD', 'FUSD', 6);
// dive = new MockERC20('DAI Virtually Equal', 'DIVE', 18); dive = new MockERC20('DAI Virtually Equal', 'DIVE', 18);
// butc = new MockERC20('Buttcoin', 'BUTC', 8); butc = new MockERC20('Buttcoin', 'BUTC', 8);
// wteth = new MockERC20('Wrapped TETH', 'WTETH', 18); wteth = new MockERC20('Wrapped TETH', 'WTETH', 18);
usxd = MockERC20(0x8E4D16886b8946dfE463fA172129eaBf4825fb09);
fusd = MockERC20(0xdc225280216822CA956738390f589c794129bd53);
dive = MockERC20(0x7ba123e4e7395A361284d069bD0D545F3f820641);
butc = MockERC20(0x88125947BBF1A6dd0FeD4B257BB3f9E1FBdCb3Cc);
wteth = MockERC20(0xC8dB65C0B9f4cf59097d4C5Bcb9e8E92B9e4e15F);
vm.label(address(usxd), 'USXD');
vm.label(address(fusd), 'FUSD');
vm.label(address(dive), 'DIVE');
vm.label(address(butc), 'BUTC');
vm.label(address(wteth), 'WTETH');
// give tokens to msg.sender for later use
mintAll(msg.sender, 1_000_000);
PartyPoolSwapImpl swapImpl = new PartyPoolSwapImpl(WETH); PartyPoolSwapImpl swapImpl = new PartyPoolSwapImpl(WETH);
PartyPoolMintImpl mintImpl = new PartyPoolMintImpl(WETH); PartyPoolMintImpl mintImpl = new PartyPoolMintImpl(WETH);
@@ -70,8 +45,6 @@ contract DeploySepolia is Script {
PROTOCOL_FEE_ADDRESS PROTOCOL_FEE_ADDRESS
); );
approveAll(address(planner) );
// //
// Deploy 3-asset pool // Deploy 3-asset pool
// //
@@ -85,35 +58,34 @@ contract DeploySepolia is Script {
_bases[0] = 10**6; _bases[0] = 10**6;
_bases[1] = 10**8; _bases[1] = 10**8;
_bases[2] = 10**18; _bases[2] = 10**18;
uint256[] memory _feesPpm = new uint256[](3);
_feesPpm[0] = 50;
_feesPpm[1] = 250;
_feesPpm[2] = 350;
uint256[] memory _prices = new uint256[](3);
_prices[0] = 1;
_prices[1] = 100000;
_prices[2] = 4000;
// mint _tokens to the deployer so it can fund the initial deposits and approve the factory
mintAll(msg.sender, 10_000);
// prepare initial deposits (10_000 units of each token, scaled by _bases) // prepare initial deposits (10_000 units of each token, scaled by _bases)
uint256[] memory initialDeposits = new uint256[](3); uint256[] memory initialDeposits = new uint256[](3);
initialDeposits[0] = 10_000 * _bases[0] / _prices[0]; initialDeposits[0] = _bases[0] * 10_000;
initialDeposits[1] = 10_000 * _bases[1] / _prices[1]; initialDeposits[1] = _bases[1] * 10_000;
initialDeposits[2] = 10_000 * _bases[2] / _prices[2]; initialDeposits[2] = _bases[2] * 10_000;
int128 kappa = LMSRStabilized.computeKappaFromSlippage(3, ABDKMath64x64.divu(1, 10), ABDKMath64x64.divu(50,10000)); // approve factory to move initial deposits
for (uint i = 0; i < tokens.length; i++) {
IERC20(tokens[i]).approve(address(planner), initialDeposits[i]);
}
// call full newPool signature on factory which will take the deposits and mint initial LP // call full newPool signature on factory which will take the deposits and mint initial LP
(IPartyPool exercisePool,) = planner.newPool( planner.newPool(
'Token Pool', 'Token Pool',
'TP', 'TP',
tokens, tokens,
kappa, _bases,
_feesPpm, ABDKMath64x64.divu(1, 10),
ABDKMath64x64.divu(1,10000),
_feePpm,
_feePpm, _feePpm,
false, false,
msg.sender, // payer: this script msg.sender, // payer: this script
msg.sender, // receiver of initial LP msg.sender, // receiver of initial LP
initialDeposits, initialDeposits,
10_000 * 10**18, 10000,
0 0
); );
@@ -132,17 +104,24 @@ contract DeploySepolia is Script {
_bases[1] = 10**6; _bases[1] = 10**6;
_bases[2] = 10**18; _bases[2] = 10**18;
// mint _tokens to the deployer so it can fund the initial deposits and approve the factory
mintAll(msg.sender, 10_000);
// prepare initial deposits (10_000 units of each token, scaled by _bases) // prepare initial deposits (10_000 units of each token, scaled by _bases)
initialDeposits = new uint256[](3); initialDeposits = new uint256[](3);
initialDeposits[0] = _bases[0] * 10_000; initialDeposits[0] = _bases[0] * 10_000;
initialDeposits[1] = _bases[1] * 10_000; initialDeposits[1] = _bases[1] * 10_000;
initialDeposits[2] = _bases[2] * 10_000; initialDeposits[2] = _bases[2] * 10_000;
// approve factory to move initial deposits
for (uint i = 0; i < tokens.length; i++) {
IERC20(tokens[i]).approve(address(planner), initialDeposits[i]);
}
// call full newPool signature on factory which will take the deposits and mint initial LP // call full newPool signature on factory which will take the deposits and mint initial LP
planner.newPool( planner.newPool(
'Stablecoin Pool', 'Stablecoin Pool',
'STAP', 'STAP',
tokens, tokens,
_bases,
ABDKMath64x64.divu(1, 10), ABDKMath64x64.divu(1, 10),
ABDKMath64x64.divu(1,10000), ABDKMath64x64.divu(1,10000),
_feePpm, _feePpm,
@@ -151,7 +130,7 @@ contract DeploySepolia is Script {
msg.sender, // payer: this script msg.sender, // payer: this script
msg.sender, // receiver of initial LP msg.sender, // receiver of initial LP
initialDeposits, initialDeposits,
10_000 * 10**18, 10000,
0 0
); );
@@ -168,16 +147,23 @@ contract DeploySepolia is Script {
_bases[0] = 10**6; _bases[0] = 10**6;
_bases[1] = 10**18; _bases[1] = 10**18;
// mint _tokens to the deployer so it can fund the initial deposits and approve the factory
mintAll(msg.sender, 10_000);
// prepare initial deposits (10_000 units of each token, scaled by _bases) // prepare initial deposits (10_000 units of each token, scaled by _bases)
initialDeposits = new uint256[](2); initialDeposits = new uint256[](2);
initialDeposits[0] = _bases[0] * 10_000; initialDeposits[0] = _bases[0] * 10_000;
initialDeposits[1] = _bases[1] * 10_000; initialDeposits[1] = _bases[1] * 10_000;
// approve factory to move initial deposits
for (uint i = 0; i < tokens.length; i++) {
IERC20(tokens[i]).approve(address(planner), initialDeposits[i]);
}
// call full newPool signature on factory which will take the deposits and mint initial LP // call full newPool signature on factory which will take the deposits and mint initial LP
planner.newPool( planner.newPool(
'Stable Pair', 'Stable Pair',
'SPAIR', 'SPAIR',
tokens, tokens,
_bases,
ABDKMath64x64.divu(8,10), // kappa = 0.8 ABDKMath64x64.divu(8,10), // kappa = 0.8
_feePpm, _feePpm,
_feePpm, _feePpm,
@@ -185,21 +171,22 @@ contract DeploySepolia is Script {
msg.sender, // payer: this script msg.sender, // payer: this script
msg.sender, // receiver of initial LP msg.sender, // receiver of initial LP
initialDeposits, initialDeposits,
10_000 * 10**18, 10000,
0 0
); );
PartyInfo info = new PartyInfo(swapImpl, mintImpl); PartyPoolViewer viewer = new PartyPoolViewer(swapImpl, mintImpl);
exercise(exercisePool, info); // give tokens to msg.sender for later use
mintAll(msg.sender, 1_000_000);
vm.stopBroadcast(); vm.stopBroadcast();
// Set ENV vars // Set ENV vars
string memory plannerStr = vm.toString(address(planner)); string memory plannerStr = vm.toString(address(planner));
string memory infoStr = vm.toString(address(info)); string memory viewerStr = vm.toString(address(viewer));
vm.setEnv('PLANNER', plannerStr); vm.setEnv('PLANNER', plannerStr);
vm.setEnv('INFO', infoStr); vm.setEnv('VIEWER', viewerStr);
vm.setEnv('USXD', vm.toString(address(usxd))); vm.setEnv('USXD', vm.toString(address(usxd)));
vm.setEnv('FUSD', vm.toString(address(fusd))); vm.setEnv('FUSD', vm.toString(address(fusd)));
vm.setEnv('DIVE', vm.toString(address(dive))); vm.setEnv('DIVE', vm.toString(address(dive)));
@@ -208,11 +195,11 @@ contract DeploySepolia is Script {
console2.log(); console2.log();
console2.log(' PartyPlanner', address(planner)); console2.log(' PartyPlanner', address(planner));
console2.log(' PartyInfo', address(info)); console2.log('PartyPoolViewer', address(viewer));
console2.log(' SwapImpl', address(swapImpl)); console2.log(' SwapImpl', address(swapImpl));
console2.log(' MintImpl', address(mintImpl)); console2.log(' MintImpl', address(mintImpl));
console2.log(' Deployer', address(deployer)); console2.log(' Deployer', address(deployer));
console2.log('BPair Deployer', address(balancedPairDeployer)); console2.log(' BPair Deployer', address(balancedPairDeployer));
console2.log(); console2.log();
console2.log(' USXD', address(usxd)); console2.log(' USXD', address(usxd));
console2.log(' FUSD', address(fusd)); console2.log(' FUSD', address(fusd));
@@ -235,59 +222,4 @@ contract DeploySepolia is Script {
wteth.mint(who, amount * 1e18); wteth.mint(who, amount * 1e18);
} }
function approveAll(address spender) internal {
usxd.approve(spender, type(uint256).max);
fusd.approve(spender, type(uint256).max);
dive.approve(spender, type(uint256).max);
butc.approve(spender, type(uint256).max);
wteth.approve(spender, type(uint256).max);
}
function exercise( IPartyPool pool, IPartyInfo info) internal {
// gather tokens and denominators
IERC20[] memory tokens = pool.allTokens();
uint256 n = tokens.length;
approveAll(address(pool));
// 1) Proportional mint (request some LP)
uint256 lpToMint = 1_234; // arbitrary non-even amount
// payer = this contract, receiver = this contract
pool.mint(msg.sender, msg.sender, lpToMint, 0);
// 2) Proportional burn (withdraw a small, non-even amount of LP)
uint256 lpToBurn = 7;
pool.burn(msg.sender, msg.sender, lpToBurn, 0, false);
// 3) Flash loan: borrow token 0 and immediately repay in callback
// deploy a temporary borrower that repays amount + fee back to the pool
MockFlashBorrower borrower = new MockFlashBorrower();
uint256 flashAmt = 53 * 10**6; // arbitrary non-even amount
uint256 flashFee = info.flashFee(pool, address(tokens[0]), flashAmt);
// Mint enough to cover the flash fee
MockERC20(address(tokens[0])).mint(address(borrower), flashFee);
// pass the pool address in data so borrower can repay back to this pool
bytes memory data = abi.encode(address(pool));
// call flashLoan (ignore success boolean/revert)
pool.flashLoan(IERC3156FlashBorrower(address(borrower)), address(tokens[0]), flashAmt, data);
// 4) swapMint (single-token mint -> LP)
uint256 swapMintAmt = 321 * 10**6; // not even
pool.swapMint(msg.sender, msg.sender, 0, swapMintAmt, 0);
// 5) regular swap (token 0 -> last token)
uint256 inputIndex = 0;
uint256 outputIndex = n > 1 ? n - 1 : 0;
uint256 maxIn = 89 * 10**6; // varied
pool.swap(msg.sender, bytes4(0), msg.sender, inputIndex, outputIndex, maxIn, int128(0), 0, false);
// 6) Collect protocol fees now (after some swaps) so some will have been moved out
pool.collectProtocolFees();
// 7) Final swap-style operation: burnSwap (burn LP then swap to single asset)
// ensure we have some LP allowance
uint256 lpForBurnSwap = 3; // non-even small amount
uint256 burnToIndex = (n > 1) ? 1 : 0;
pool.burnSwap(msg.sender, msg.sender, lpForBurnSwap, burnToIndex, 0, false);
}
} }

View File

@@ -18,6 +18,7 @@ interface IPartyPlanner is IOwnable {
/// @param name LP token name /// @param name LP token name
/// @param symbol LP token symbol /// @param symbol LP token symbol
/// @param tokens token addresses (n) /// @param tokens token addresses (n)
/// @param bases scaling bases for each token (n) - used when converting to/from internal 64.64 amounts
/// @param tradeFrac trade fraction in 64.64 fixed-point (as used by LMSR) /// @param tradeFrac trade fraction in 64.64 fixed-point (as used by LMSR)
/// @param targetSlippage target slippage in 64.64 fixed-point (as used by LMSR) /// @param targetSlippage target slippage in 64.64 fixed-point (as used by LMSR)
/// @param swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations /// @param swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations
@@ -34,6 +35,7 @@ interface IPartyPlanner is IOwnable {
string memory name, string memory name,
string memory symbol, string memory symbol,
IERC20[] memory tokens, IERC20[] memory tokens,
uint256[] memory bases,
int128 tradeFrac, int128 tradeFrac,
int128 targetSlippage, int128 targetSlippage,
uint256 swapFeePpm, uint256 swapFeePpm,
@@ -51,6 +53,7 @@ interface IPartyPlanner is IOwnable {
/// @param name LP token name /// @param name LP token name
/// @param symbol LP token symbol /// @param symbol LP token symbol
/// @param tokens token addresses (n) /// @param tokens token addresses (n)
/// @param bases scaling bases for each token (n) - used when converting to/from internal 64.64 amounts
/// @param kappa liquidity parameter κ in 64.64 fixed-point used to derive b = κ * S(q) /// @param kappa liquidity parameter κ in 64.64 fixed-point used to derive b = κ * S(q)
/// @param swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations /// @param swapFeePpm fee in parts-per-million, taken from swap input amounts before LMSR calculations
/// @param flashFeePpm fee in parts-per-million, taken for flash loans /// @param flashFeePpm fee in parts-per-million, taken for flash loans
@@ -66,6 +69,7 @@ interface IPartyPlanner is IOwnable {
string memory name, string memory name,
string memory symbol, string memory symbol,
IERC20[] memory tokens, IERC20[] memory tokens,
uint256[] memory bases,
int128 kappa, int128 kappa,
uint256 swapFeePpm, uint256 swapFeePpm,
uint256 flashFeePpm, uint256 flashFeePpm,

View File

@@ -61,8 +61,8 @@ interface IPartyPool is IERC20Metadata, IOwnable {
IERC20 indexed tokenOut, IERC20 indexed tokenOut,
uint256 amountIn, uint256 amountIn,
uint256 amountOut, uint256 amountOut,
uint256 lpFee, // taken from the output token uint256 lpFee,
uint256 protocolFee // taken from the output token uint256 protocolFee
); );
event Flash( event Flash(
@@ -97,11 +97,8 @@ interface IPartyPool is IERC20Metadata, IOwnable {
/// @dev denominators()[i] is the base for tokens[i]. These bases are chosen by deployer and must match token decimals. /// @dev denominators()[i] is the base for tokens[i]. These bases are chosen by deployer and must match token decimals.
function denominators() external view returns (uint256[] memory); function denominators() external view returns (uint256[] memory);
/// @notice Per-asset swap fees in ppm. Fees are applied on input; for asset-to-asset swaps, the effective pair fee is 1 - (1 - f_i)(1 - f_j). /// @notice Per-swap fee in parts-per-million (ppm). Fee is taken from input amounts before LMSR computations.
function fees() external view returns (uint256[] memory); function swapFeePpm() external view returns (uint256);
/// @notice Effective combined fee in ppm for the given asset pair (i as input, j as output).
function fee(uint256 i, uint256 j) external view returns (uint256);
/// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts. /// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts.
function flashFeePpm() external view returns (uint256); function flashFeePpm() external view returns (uint256);
@@ -120,9 +117,9 @@ interface IPartyPool is IERC20Metadata, IOwnable {
/// @notice Callable by anyone, sends any owed protocol fees to the protocol fee address. /// @notice Callable by anyone, sends any owed protocol fees to the protocol fee address.
function collectProtocolFees() external; function collectProtocolFees() external;
/// @notice Liquidity parameter κ (Q64.64) used by the LMSR kernel: b = κ * S(q) /// @notice Fixed LMSR curvature parameter b (Q64.64) Larger values allow more liquidity to be taken with less price impact.
/// @dev Pools are constructed with a κ value; this getter exposes the κ used by the pool. /// @dev Pools are constructed with a fixed b; this getter exposes the b used by the pool.
function kappa() external view returns (int128); function bFixed() external view returns (int128);
/// @notice If a security problem is found, the vault owner may call this function to permanently disable swap and /// @notice If a security problem is found, the vault owner may call this function to permanently disable swap and
/// mint functionality, leaving only burns (withdrawals) working. /// mint functionality, leaving only burns (withdrawals) working.
@@ -166,29 +163,27 @@ interface IPartyPool is IERC20Metadata, IOwnable {
/// @param outputTokenIndex index of output token /// @param outputTokenIndex index of output token
/// @param maxAmountIn maximum gross input allowed (inclusive of fee) /// @param maxAmountIn maximum gross input allowed (inclusive of fee)
/// @param limitPrice maximum acceptable marginal price (pass 0 to ignore) /// @param limitPrice maximum acceptable marginal price (pass 0 to ignore)
/// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, inFee fee taken from input amount /// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, fee fee amount taken
function swapAmounts( function swapAmounts(
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
uint256 maxAmountIn, uint256 maxAmountIn,
int128 limitPrice int128 limitPrice
) external view returns (uint256 amountIn, uint256 amountOut, uint256 inFee); ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee);
/// @notice Swap input token inputTokenIndex -> token outputTokenIndex. Payer must approve token inputTokenIndex. /// @notice Swap input token inputTokenIndex -> token outputTokenIndex. Payer must approve token inputTokenIndex.
/// @dev This function transfers the exact gross input (including fee) from payer and sends the computed output to receiver. /// @dev This function transfers the exact gross input (including fee) from payer and sends the computed output to receiver.
/// Non-standard tokens (fee-on-transfer, rebasers) are rejected via balance checks. /// Non-standard tokens (fee-on-transfer, rebasers) are rejected via balance checks.
/// @param payer address of the account that pays for the swap /// @param payer address of the account that pays for the swap
/// @param selector If zero, then regular ERC20 approvals must be given by the payere to the pool to move the required input amount. If this selector is nonzero, then a callback style funding mechanism is used where the given selector is invoked on the payer, passing the arguments of (address inputToken, uint256 inputAmount). The callback function must send the given amount of input coin to the pool in ordr to continue the swap transaction, otherwise "Insufficient funds" is thrown.
/// @param receiver address that will receive the output tokens /// @param receiver address that will receive the output tokens
/// @param inputTokenIndex index of input asset /// @param inputTokenIndex index of input asset
/// @param outputTokenIndex index of output asset /// @param outputTokenIndex index of output asset
/// @param maxAmountIn maximum amount of token inputTokenIndex (uint256) to transfer in (inclusive of fees) /// @param maxAmountIn maximum amount of token inputTokenIndex (uint256) to transfer in (inclusive of fees)
/// @param limitPrice maximum acceptable marginal price (64.64 fixed point). Pass 0 to ignore. /// @param limitPrice maximum acceptable marginal price (64.64 fixed point). Pass 0 to ignore.
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
/// @return amountIn actual input used (uint256), amountOut actual output sent (uint256), inFee fee taken from the input (uint256) /// @return amountIn actual input used (uint256), amountOut actual output sent (uint256), fee fee taken from the input (uint256)
function swap( function swap(
address payer, address payer,
bytes4 selector,
address receiver, address receiver,
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
@@ -196,7 +191,7 @@ interface IPartyPool is IERC20Metadata, IOwnable {
int128 limitPrice, int128 limitPrice,
uint256 deadline, uint256 deadline,
bool unwrap bool unwrap
) external payable returns (uint256 amountIn, uint256 amountOut, uint256 inFee); ) external payable returns (uint256 amountIn, uint256 amountOut, uint256 fee);
/// @notice Swap up to the price limit; computes max input to reach limit then performs swap. /// @notice Swap up to the price limit; computes max input to reach limit then performs swap.
/// @dev If balances prevent fully reaching the limit, the function caps and returns actuals. /// @dev If balances prevent fully reaching the limit, the function caps and returns actuals.
@@ -207,7 +202,7 @@ interface IPartyPool is IERC20Metadata, IOwnable {
/// @param outputTokenIndex index of output asset /// @param outputTokenIndex index of output asset
/// @param limitPrice target marginal price to reach (must be > 0) /// @param limitPrice target marginal price to reach (must be > 0)
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
/// @return amountInUsed actual input used excluding fee (uint256), amountOut actual output sent (uint256), inFee fee taken from the input (uint256) /// @return amountInUsed actual input used excluding fee (uint256), amountOut actual output sent (uint256), fee fee taken from the input (uint256)
function swapToLimit( function swapToLimit(
address payer, address payer,
address receiver, address receiver,
@@ -216,7 +211,7 @@ interface IPartyPool is IERC20Metadata, IOwnable {
int128 limitPrice, int128 limitPrice,
uint256 deadline, uint256 deadline,
bool unwrap bool unwrap
) external payable returns (uint256 amountInUsed, uint256 amountOut, uint256 inFee); ) external payable returns (uint256 amountInUsed, uint256 amountOut, uint256 fee);
/// @notice Single-token mint: deposit a single token, charge swap-LMSR cost, and mint LP. /// @notice Single-token mint: deposit a single token, charge swap-LMSR cost, and mint LP.
/// @dev swapMint executes as an exact-in planned swap followed by proportional scaling of qInternal. /// @dev swapMint executes as an exact-in planned swap followed by proportional scaling of qInternal.
@@ -226,38 +221,39 @@ interface IPartyPool is IERC20Metadata, IOwnable {
/// @param inputTokenIndex index of the input token /// @param inputTokenIndex index of the input token
/// @param maxAmountIn maximum uint token input (inclusive of fee) /// @param maxAmountIn maximum uint token input (inclusive of fee)
/// @param deadline optional deadline /// @param deadline optional deadline
/// @return amountInUsed actual input used (uint256), lpMinted actual LP minted (uint256), inFee fee taken from the input (uint256) /// @return lpMinted actual LP minted (uint)
function swapMint( function swapMint(
address payer, address payer,
address receiver, address receiver,
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 maxAmountIn, uint256 maxAmountIn,
uint256 deadline uint256 deadline
) external payable returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee); ) external payable returns (uint256 lpMinted);
/// @notice Burn LP tokens then swap the redeemed proportional basket into a single asset `outputTokenIndex` and send to receiver. /// @notice Burn LP tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
/// @dev The function burns LP tokens (authorization via allowance if needed), sends the single-asset payout and updates LMSR state. /// @dev The function burns LP tokens (authorization via allowance if needed), sends the single-asset payout and updates LMSR state.
/// @param payer who burns LP tokens /// @param payer who burns LP tokens
/// @param receiver who receives the single asset /// @param receiver who receives the single asset
/// @param lpAmount amount of LP tokens to burn /// @param lpAmount amount of LP tokens to burn
/// @param outputTokenIndex index of target asset to receive /// @param inputTokenIndex index of target asset to receive
/// @param deadline optional deadline /// @param deadline optional deadline
/// @return amountOut uint amount of asset outputTokenIndex sent to receiver /// @return amountOutUint uint amount of asset inputTokenIndex sent to receiver
/// @return outFee uint amount of output asset kept by the LP's and protocol as a fee
function burnSwap( function burnSwap(
address payer, address payer,
address receiver, address receiver,
uint256 lpAmount, uint256 lpAmount,
uint256 outputTokenIndex, uint256 inputTokenIndex,
uint256 deadline, uint256 deadline,
bool unwrap bool unwrap
) external returns (uint256 amountOut, uint256 outFee); ) external returns (uint256 amountOutUint);
/// @dev Initiate a flash loan. /**
/// @param receiver The receiver of the tokens in the loan, and the receiver of the callback. * @dev Initiate a flash loan.
/// @param token The loan currency. * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
/// @param amount The amount of tokens lent. * @param token The loan currency.
/// @param data Arbitrary data structure, intended to contain user-defined parameters. * @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan( function flashLoan(
IERC3156FlashBorrower receiver, IERC3156FlashBorrower receiver,
address token, address token,

View File

@@ -1,32 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IPartyPool} from "./IPartyPool.sol";
import {NativeWrapper} from "./NativeWrapper.sol";
import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
interface IPartyPoolDeployer {
struct DeployParams {
address owner;
string memory name;
string memory symbol;
IERC20[] memory tokens;
int128 kappa;
uint256[] memory fees;
uint256 flashFeePpm;
uint256 protocolFeePpm;
address protocolFeeAddress;
NativeWrapper wrapper;
PartyPoolSwapImpl swapImpl;
PartyPoolMintImpl mintImpl;
}
function deploy(DeployParams memory params) external returns (IPartyPool pool);
function params() external returns (DeployParams memory params);
}

View File

@@ -3,11 +3,7 @@ pragma solidity ^0.8.30;
import {IPartyPool} from "./IPartyPool.sol"; import {IPartyPool} from "./IPartyPool.sol";
interface IPartyInfo { interface IPartyPoolViewer {
/// @notice returns true iff the pool is not killed and has been initialized with liquidity.
function working(IPartyPool pool) external view returns (bool);
/// @notice Marginal price of `base` denominated in `quote` as Q64.64. /// @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. /// @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). /// Useful for off-chain quoting; raw 64.64 value is returned (no scaling to token units).
@@ -38,27 +34,33 @@ interface IPartyInfo {
/// @param inputTokenIndex index of input token /// @param inputTokenIndex index of input token
/// @param outputTokenIndex index of output token /// @param outputTokenIndex index of output token
/// @param limitPrice target marginal price to reach (must be > 0) /// @param limitPrice target marginal price to reach (must be > 0)
/// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, inFee fee taken from input amount /// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, fee fee amount taken
function swapToLimitAmounts( function swapToLimitAmounts(
IPartyPool pool, IPartyPool pool,
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
int128 limitPrice int128 limitPrice
) external view returns (uint256 amountIn, uint256 amountOut, uint256 inFee); ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee);
/// @notice Calculate the amounts for a swap mint operation /// @notice Calculate the amounts for a swap mint operation
/// @dev This is a pure view function that computes swap mint amounts from provided state /// @dev This is a pure view function that computes swap mint amounts from provided state
/// @param inputTokenIndex index of the input token /// @param inputTokenIndex index of the input token
/// @param maxAmountIn maximum amount of token to deposit (inclusive of fee) /// @param maxAmountIn maximum amount of token to deposit (inclusive of fee)
function swapMintAmounts(IPartyPool pool, uint256 inputTokenIndex, uint256 maxAmountIn) external view function swapMintAmounts(IPartyPool pool, uint256 inputTokenIndex, uint256 maxAmountIn) external view
returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee); returns (uint256 amountInUsed, uint256 fee, uint256 lpMinted);
/// @notice Calculate the amounts for a burn swap operation /// @notice Calculate the amounts for a burn swap operation
/// @dev This is a pure view function that computes burn swap amounts from provided state /// @dev This is a pure view function that computes burn swap amounts from provided state
/// @param lpAmount amount of LP _tokens to burn /// @param lpAmount amount of LP _tokens to burn
/// @param outputTokenIndex index of target asset to receive /// @param inputTokenIndex index of target asset to receive
function burnSwapAmounts(IPartyPool pool, uint256 lpAmount, uint256 outputTokenIndex) external view function burnSwapAmounts(IPartyPool pool, uint256 lpAmount, uint256 inputTokenIndex) external view
returns (uint256 amountOut, uint256 outFee); returns (uint256 amountOut);
/// @notice Compute repayment amounts (principal + flash fee) for a proposed flash loan.
/// @param loanAmounts array of per-token loan amounts; must match the pool's token ordering.
/// @return repaymentAmounts array where repaymentAmounts[i] = loanAmounts[i] + ceil(loanAmounts[i] * flashFeePpm)
function flashRepaymentAmounts(IPartyPool pool, uint256[] memory loanAmounts) external view
returns (uint256[] memory repaymentAmounts);
/** /**
* @dev The amount of currency available to be lent. * @dev The amount of currency available to be lent.

View File

@@ -12,7 +12,8 @@ library LMSRStabilized {
using ABDKMath64x64 for int128; using ABDKMath64x64 for int128;
struct State { struct State {
int128 kappa; // liquidity parameter κ (64.64 fixed point) uint256 nAssets;
int128 bFixed; // fixed b curvature (Q64.64)
int128[] qInternal; // cached internal balances in 64.64 fixed-point format int128[] qInternal; // cached internal balances in 64.64 fixed-point format
} }
@@ -25,9 +26,10 @@ library LMSRStabilized {
function init( function init(
State storage s, State storage s,
int128[] memory initialQInternal, int128[] memory initialQInternal,
int128 kappa int128 bFixed
) internal { ) internal {
// Initialize qInternal cache s.nAssets = initialQInternal.length;
if (s.qInternal.length != initialQInternal.length) { if (s.qInternal.length != initialQInternal.length) {
s.qInternal = new int128[](initialQInternal.length); s.qInternal = new int128[](initialQInternal.length);
} }
@@ -39,9 +41,73 @@ library LMSRStabilized {
int128 total = _computeSizeMetric(s.qInternal); int128 total = _computeSizeMetric(s.qInternal);
require(total > int128(0), "LMSR: total zero"); require(total > int128(0), "LMSR: total zero");
// Set kappa directly (caller provides kappa) require(bFixed > int128(0), "LMSR: b<=0");
s.kappa = kappa; s.bFixed = bFixed;
require(s.kappa > int128(0), "LMSR: kappa>0"); }
/* --------------------
Virtual offset helpers (pure) for initialization
-------------------- */
/// @notice Compute per-asset virtual offsets v so that the initial marginal price between `base` and `quote`
/// equals `targetPrice` (Q64.64). Returns an array v with v_base and v_quote adjusted and others zero.
/// @dev Given reserves r, we want s = r + v with s_quote - s_base = b * ln(targetPrice).
/// Let deltaDesired = b*ln(targetPrice), deltaCurrent = r_quote - r_base, then
/// let adj = deltaDesired - deltaCurrent; choose v_base = -adj/2, v_quote = adj/2, others 0.
function computeOffsetsForPricePair(
int128 b,
int128[] memory reservesInternal,
uint256 baseIndex,
uint256 quoteIndex,
int128 targetPrice
) internal pure returns (int128[] memory vOffsets) {
require(b > int128(0), "LMSR: b<=0");
uint256 n = reservesInternal.length;
require(baseIndex < n && quoteIndex < n, "LMSR: idx");
vOffsets = new int128[](n);
// adj = b * ln(targetPrice) - (r_quote - r_base)
int128 deltaDesired = b.mul(_ln(targetPrice));
int128 deltaCurrent = reservesInternal[quoteIndex].sub(reservesInternal[baseIndex]);
int128 adj = deltaDesired.sub(deltaCurrent);
int128 two = ABDKMath64x64.fromUInt(2);
// v_base = -adj/2; v_quote = adj/2
vOffsets[baseIndex] = adj.neg().div(two);
vOffsets[quoteIndex] = adj.div(two);
return vOffsets;
}
/// @notice Compute per-asset virtual offsets v to match a vector of relative log-prices (Q64.64).
/// @dev logPrices[i] should represent ln(p_i / p_ref) for a chosen reference asset ref (e.g., ref = 0 => logPrices[0] = 0).
/// We set v_0 = 0 and for i>0 require (v_i - v_0) = b*(logPrices[i] - logPrices[0]) - (r_i - r_0).
/// Note: adding a constant to all v does not change prices; callers may shift v uniformly if they want S>0 margin.
function computeOffsetsForLogPrices(
int128 b,
int128[] memory reservesInternal,
uint256 referenceIndex,
int128[] memory logPrices
) internal pure returns (int128[] memory vOffsets) {
require(b > int128(0), "LMSR: b<=0");
uint256 n = reservesInternal.length;
require(logPrices.length == n, "LMSR: length mismatch");
require(referenceIndex < n, "LMSR: ref idx");
vOffsets = new int128[](n);
// Set v_ref = 0, solve differences for others
uint256 ref = referenceIndex;
int128 logP_ref = logPrices[ref];
for (uint256 i = 0; i < n; ) {
if (i != ref) {
int128 desiredDiff = b.mul(logPrices[i].sub(logP_ref)); // b*(ln p_i - ln p_ref)
int128 currentDiff = reservesInternal[i].sub(reservesInternal[ref]); // r_i - r_ref
vOffsets[i] = desiredDiff.sub(currentDiff); // v_i - v_ref with v_ref = 0
}
unchecked { i++; }
}
return vOffsets;
} }
/* -------------------- /* --------------------
@@ -50,14 +116,13 @@ library LMSRStabilized {
/// @notice Cost C(q) = b * (M + ln(Z)) /// @notice Cost C(q) = b * (M + ln(Z))
function cost(State storage s) internal view returns (int128) { function cost(State storage s) internal view returns (int128) {
return cost(s.kappa, s.qInternal); int128 b = _computeB(s);
return cost(b, s.qInternal);
} }
/// @notice Pure version: Cost C(q) = b * (M + ln(Z)) /// @notice Pure version: Cost C(q) = b * (M + ln(Z))
function cost(int128 kappa, int128[] memory qInternal) internal pure returns (int128) { function cost(int128 b, int128[] memory qInternal) internal pure returns (int128) {
int128 sizeMetric = _computeSizeMetric(qInternal); require(b > int128(0), "LMSR: b<=0");
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
(int128 M, int128 Z) = _computeMAndZ(b, qInternal); (int128 M, int128 Z) = _computeMAndZ(b, qInternal);
int128 lnZ = _ln(Z); int128 lnZ = _ln(Z);
int128 inner = M.add(lnZ); int128 inner = M.add(lnZ);
@@ -95,7 +160,8 @@ library LMSRStabilized {
int128 a, int128 a,
int128 limitPrice int128 limitPrice
) internal view returns (int128 amountIn, int128 amountOut) { ) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForExactInput(s.kappa, s.qInternal, i, j, a, limitPrice); int128 b = _computeB(s);
return swapAmountsForExactInput(s.nAssets, b, s.qInternal, i, j, a, limitPrice);
} }
/// @notice Pure version: Closed-form asset-i -> asset-j amountOut in 64.64 fixed-point format (fee-free kernel) /// @notice Pure version: Closed-form asset-i -> asset-j amountOut in 64.64 fixed-point format (fee-free kernel)
@@ -110,7 +176,8 @@ library LMSRStabilized {
/// ///
/// NOTE: Kernel is fee-free; fees should be handled by the wrapper/token layer. /// NOTE: Kernel is fee-free; fees should be handled by the wrapper/token layer.
/// ///
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param nAssets Number of assets in the pool
/// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of input asset /// @param i Index of input asset
/// @param j Index of output asset /// @param j Index of output asset
@@ -119,57 +186,46 @@ library LMSRStabilized {
/// @return amountIn Actual amount of input asset used (may be less than `a` if limited by price) /// @return amountIn Actual amount of input asset used (may be less than `a` if limited by price)
/// @return amountOut Amount of output asset j in 64.64 fixed-point format /// @return amountOut Amount of output asset j in 64.64 fixed-point format
function swapAmountsForExactInput( function swapAmountsForExactInput(
int128 kappa, uint256 nAssets,
int128 b,
int128[] memory qInternal, int128[] memory qInternal,
uint256 i, uint256 i,
uint256 j, uint256 j,
int128 a, int128 a,
int128 limitPrice int128 limitPrice
) internal pure returns (int128 amountIn, int128 amountOut) { ) internal pure returns (int128 amountIn, int128 amountOut) {
require(i < nAssets && j < nAssets, "LMSR: idx");
// Initialize amountIn to full amount (will be adjusted if limit price is hit) // Initialize amountIn to full amount (will be adjusted if limit price is hit)
amountIn = a; amountIn = a;
// Compute b and ensure positivity before deriving invB // Ensure b > 0 and derive invB
int128 sizeMetric = _computeSizeMetric(qInternal); require(b > int128(0), "LMSR: b<=0");
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
// Precompute reciprocal of b to avoid repeated divisions
int128 invB = ABDKMath64x64.div(ONE, b); int128 invB = ABDKMath64x64.div(ONE, b);
// Compute r0 = exp((q_i - q_j) / b) directly using invB // Compute r0 = exp((q_i - q_j) / b) directly using invB (always > 0)
int128 r0 = _exp(qInternal[i].sub(qInternal[j]).mul(invB)); int128 r0 = _exp(qInternal[i].sub(qInternal[j]).mul(invB));
// If a positive limitPrice is given, determine whether the full `a` would // If a positive limitPrice is given, determine whether the full `a` would
// push the marginal price p_i/p_j beyond the limit; if so, truncate `a`. // push the marginal price p_i/p_j beyond the limit; if so, truncate `a`.
// Marginal price ratio evolves as r(t) = r0 * exp(t/b) (since e_i multiplies by exp(t/b)) // Marginal price ratio evolves as r(t) = r0 * exp(t/b)
if (limitPrice > int128(0)) { if (limitPrice > int128(0)) {
// If limitPrice <= current price, we revert (caller must choose a limit > current price to allow any fill)
if (limitPrice <= r0) { if (limitPrice <= r0) {
revert("LMSR: limitPrice <= current price"); revert("LMSR: limitPrice <= current price");
} }
// Compute a_limit directly from ln(limit / r0): a_limit = b * ln(limit / r0)
int128 ratioLimitOverR0 = limitPrice.div(r0); int128 ratioLimitOverR0 = limitPrice.div(r0);
require(ratioLimitOverR0 > int128(0), "LMSR: ratio<=0"); require(ratioLimitOverR0 > int128(0), "LMSR: ratio<=0");
int128 aLimitOverB = _ln(ratioLimitOverR0); // > 0 int128 aLimitOverB = _ln(ratioLimitOverR0); // > 0
// aLimit = b * aLimitOverB
int128 aLimit64 = b.mul(aLimitOverB); int128 aLimit64 = b.mul(aLimitOverB);
// If computed aLimit is less than the requested a, use the truncated value.
if (aLimit64 < a) { if (aLimit64 < a) {
amountIn = aLimit64; // Store the truncated input amount amountIn = aLimit64;
a = aLimit64; // Use truncated amount for calculations a = aLimit64;
} else {
// no truncation needed
} }
} }
// compute a/b safely and guard against very large arguments to exp() // compute a/b safely and guard against very large arguments to exp()
int128 aOverB = a.mul(invB); int128 aOverB = a.mul(invB);
// Protect exp from enormous inputs (consistent with recenter thresholds)
require(aOverB <= EXP_LIMIT, "LMSR: a/b too large (would overflow exp)"); require(aOverB <= EXP_LIMIT, "LMSR: a/b too large (would overflow exp)");
// Use the closed-form fee-free formula: // Use the closed-form fee-free formula:
@@ -178,17 +234,14 @@ library LMSRStabilized {
int128 oneMinusExpNeg = ONE.sub(expNeg); int128 oneMinusExpNeg = ONE.sub(expNeg);
int128 inner = ONE.add(r0.mul(oneMinusExpNeg)); int128 inner = ONE.add(r0.mul(oneMinusExpNeg));
// If inner <= 0 then cap output to the current balance q_j (cannot withdraw more than q_j) // If inner <= 0 then return zero (numeric guard; reserve caps are enforced by wrapper)
if (inner <= int128(0)) { if (inner <= int128(0)) {
int128 qj64 = qInternal[j]; return (amountIn, int128(0));
return (amountIn, qj64);
} }
int128 lnInner = _ln(inner); int128 lnInner = _ln(inner);
int128 b_lnInner = b.mul(lnInner); amountOut = b.mul(lnInner);
amountOut = b_lnInner;
// Safety check
if (amountOut <= 0) { if (amountOut <= 0) {
return (0, 0); return (0, 0);
} }
@@ -212,7 +265,8 @@ library LMSRStabilized {
uint256 j, uint256 j,
int128 limitPrice int128 limitPrice
) internal view returns (int128 amountIn, int128 amountOut) { ) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForPriceLimit(s.kappa, s.qInternal, i, j, limitPrice); int128 b = _computeB(s);
return swapAmountsForPriceLimit(s.nAssets, b, s.qInternal, i, j, limitPrice);
} }
/// @notice Pure version: Maximum input/output pair possible when swapping from asset i to asset j /// @notice Pure version: Maximum input/output pair possible when swapping from asset i to asset j
@@ -221,7 +275,8 @@ library LMSRStabilized {
/// and the corresponding output amount (amountOut). If the output would exceed the /// and the corresponding output amount (amountOut). If the output would exceed the
/// j-balance, amountOut is capped and amountIn is solved for the capped output. /// j-balance, amountOut is capped and amountIn is solved for the capped output.
/// ///
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param nAssets Number of assets in the pool
/// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of input asset /// @param i Index of input asset
/// @param j Index of output asset /// @param j Index of output asset
@@ -229,74 +284,41 @@ library LMSRStabilized {
/// @return amountIn Maximum input amount in 64.64 fixed-point format that reaches the price limit /// @return amountIn Maximum input amount in 64.64 fixed-point format that reaches the price limit
/// @return amountOut Corresponding maximum output amount in 64.64 fixed-point format /// @return amountOut Corresponding maximum output amount in 64.64 fixed-point format
function swapAmountsForPriceLimit( function swapAmountsForPriceLimit(
int128 kappa, uint256 nAssets,
int128 b,
int128[] memory qInternal, int128[] memory qInternal,
uint256 i, uint256 i,
uint256 j, uint256 j,
int128 limitPrice int128 limitPrice
) internal pure returns (int128 amountIn, int128 amountOut) { ) internal pure returns (int128 amountIn, int128 amountOut) {
require(i < nAssets && j < nAssets, "LMSR: idx");
require(limitPrice > int128(0), "LMSR: limitPrice <= 0"); require(limitPrice > int128(0), "LMSR: limitPrice <= 0");
// Compute b and ensure positivity before deriving invB // Ensure positivity and derive invB
int128 sizeMetric = _computeSizeMetric(qInternal); require(b > int128(0), "LMSR: b<=0");
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
// Precompute reciprocal of b to avoid repeated divisions
int128 invB = ABDKMath64x64.div(ONE, b); int128 invB = ABDKMath64x64.div(ONE, b);
// Compute r0 = exp((q_i - q_j) / b) directly using invB // Compute r0 = exp((q_i - q_j) / b)
int128 r0 = _exp(qInternal[i].sub(qInternal[j]).mul(invB)); int128 r0 = _exp(qInternal[i].sub(qInternal[j]).mul(invB));
// If current price already exceeds or equals limit, revert the same way swapAmountsForExactInput does. // If current price already exceeds or equals limit, revert (no room to move)
if (r0 >= limitPrice) { if (r0 >= limitPrice) {
revert("LMSR: limitPrice <= current price"); revert("LMSR: limitPrice <= current price");
} }
// Calculate the price change factor: limitPrice/r0
int128 priceChangeFactor = limitPrice.div(r0);
// ln(priceChangeFactor) gives us the maximum allowed delta in the exponent
int128 maxDeltaExponent = _ln(priceChangeFactor);
// Maximum input capable of reaching the price limit:
// x_max = b * ln(limitPrice / r0) // x_max = b * ln(limitPrice / r0)
int128 priceChangeFactor = limitPrice.div(r0);
int128 maxDeltaExponent = _ln(priceChangeFactor);
int128 amountInMax = b.mul(maxDeltaExponent); int128 amountInMax = b.mul(maxDeltaExponent);
// The maximum output y corresponding to that input: // y_max = b * ln(1 + r0 * (1 - exp(-x_max/b)))
// y = b * ln(1 + (e_i/e_j) * (1 - exp(-x_max/b)))
int128 expTerm = ONE.sub(_exp(maxDeltaExponent.neg())); int128 expTerm = ONE.sub(_exp(maxDeltaExponent.neg()));
int128 innerTerm = r0.mul(expTerm); int128 innerTerm = r0.mul(expTerm);
int128 lnTerm = _ln(ONE.add(innerTerm)); int128 lnTerm = _ln(ONE.add(innerTerm));
int128 maxOutput = b.mul(lnTerm); int128 maxOutput = b.mul(lnTerm);
// Current balance of asset j (in 64.64)
int128 qj64 = qInternal[j];
// Initialize outputs to the computed maxima
amountIn = amountInMax; amountIn = amountInMax;
amountOut = maxOutput; amountOut = maxOutput;
// If the calculated maximum output exceeds the balance, cap output and solve for input.
if (maxOutput > qj64) {
amountOut = qj64;
// Solve inverse relation for input given capped output:
// Given y = amountOut, let E = exp(y/b). Then
// 1 - exp(-a/b) = (E - 1) / r0
// exp(-a/b) = 1 - (E - 1) / r0 = (r0 + 1 - E) / r0
// a = -b * ln( (r0 + 1 - E) / r0 ) = b * ln( r0 / (r0 + 1 - E) )
int128 E = _exp(amountOut.mul(invB)); // exp(y/b)
int128 rhs = r0.add(ONE).sub(E); // r0 + 1 - E
// If rhs <= 0 due to numerical issues, fall back to amountInMax
if (rhs <= int128(0)) {
amountIn = amountInMax;
} else {
amountIn = b.mul(_ln(r0.div(rhs)));
}
}
return (amountIn, amountOut); return (amountIn, amountOut);
} }
@@ -311,7 +333,8 @@ library LMSRStabilized {
uint256 i, uint256 i,
int128 a int128 a
) internal view returns (int128 amountIn, int128 amountOut) { ) internal view returns (int128 amountIn, int128 amountOut) {
return swapAmountsForMint(s.kappa, s.qInternal, i, a); int128 b = _computeB(s);
return swapAmountsForMint(s.nAssets, b, s.qInternal, i, a);
} }
/// @notice Pure version: Compute LP-size increase when minting from a single-token input using bisection only. /// @notice Pure version: Compute LP-size increase when minting from a single-token input using bisection only.
@@ -320,28 +343,30 @@ library LMSRStabilized {
/// where x_j(α) is the input to swap i->j that yields y_j = α*q_j and /// where x_j(α) is the input to swap i->j that yields y_j = α*q_j and
/// x_j = b * ln( r0_j / (r0_j + 1 - exp(y_j / b)) ), r0_j = exp((q_i - q_j)/b). /// x_j = b * ln( r0_j / (r0_j + 1 - exp(y_j / b)) ), r0_j = exp((q_i - q_j)/b).
/// Bisection is used (no Newton) to keep implementation compact and gas-friendly. /// Bisection is used (no Newton) to keep implementation compact and gas-friendly.
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param nAssets Number of assets in the pool
/// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of input asset /// @param i Index of input asset
/// @param a Amount of input asset (in int128 format, 64.64 fixed-point) /// @param a Amount of input asset (in int128 format, 64.64 fixed-point)
/// @return amountIn Actual amount of input consumed /// @return amountIn Actual amount of input consumed
/// @return amountOut LP size-metric increase (alpha * S) /// @return amountOut LP size-metric increase (alpha * S)
function swapAmountsForMint( function swapAmountsForMint(
int128 kappa, uint256 nAssets,
int128 b,
int128[] memory qInternal, int128[] memory qInternal,
uint256 i, uint256 i,
int128 a int128 a
) internal pure returns (int128 amountIn, int128 amountOut) { ) internal pure returns (int128 amountIn, int128 amountOut) {
uint256 n = qInternal.length; require(i < nAssets, "LMSR: idx");
require(i < n, "LMSR: idx");
require(a > int128(0), "LMSR: amount <= 0"); require(a > int128(0), "LMSR: amount <= 0");
int128 sizeMetric = _computeSizeMetric(qInternal); // Compute size metric S for output computation; use provided b for curvature
require(sizeMetric > int128(0), "LMSR: size metric zero"); int128 S = _computeSizeMetric(qInternal);
int128 b = kappa.mul(sizeMetric); require(S > int128(0), "LMSR: size metric zero");
require(b > int128(0), "LMSR: b<=0"); require(b > int128(0), "LMSR: b<=0");
int128 invB = ABDKMath64x64.div(ONE, b); int128 invB = ABDKMath64x64.div(ONE, b);
int128 S = sizeMetric;
uint256 n = nAssets;
// Precompute r0_j = exp((q_i - q_j) / b) for all j to avoid recomputing during search. // Precompute r0_j = exp((q_i - q_j) / b) for all j to avoid recomputing during search.
int128[] memory r0 = new int128[](n); int128[] memory r0 = new int128[](n);
@@ -519,8 +544,9 @@ library LMSRStabilized {
State storage s, State storage s,
uint256 i, uint256 i,
int128 alpha int128 alpha
) internal view returns (int128 amountIn, int128 amountOut) { ) internal view returns (int128 amountOut, int128 amountIn) {
return swapAmountsForBurn(s.kappa, s.qInternal, i, alpha); int128 b = _computeB(s);
return swapAmountsForBurn(s.nAssets, b, s.qInternal, i, alpha);
} }
/// @notice Pure version: Compute single-asset payout when burning a proportional share alpha of the pool. /// @notice Pure version: Compute single-asset payout when burning a proportional share alpha of the pool.
@@ -532,27 +558,30 @@ library LMSRStabilized {
/// - cap output to q_local[i] when necessary (solve inverse for input used) /// - cap output to q_local[i] when necessary (solve inverse for input used)
/// Treat any per-asset rhs<=0 as "this asset contributes zero" (do not revert). /// Treat any per-asset rhs<=0 as "this asset contributes zero" (do not revert).
/// Revert only if the final single-asset payout is zero. /// Revert only if the final single-asset payout is zero.
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param nAssets Number of assets in the pool
/// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of output asset /// @param i Index of output asset
/// @param alpha Proportional share to burn (0 < alpha <= 1) /// @param alpha Proportional share to burn (0 < alpha <= 1)
/// @return amountIn LP size-metric redeemed (alpha * S)
/// @return amountOut Amount of asset i received (in 64.64 fixed-point) /// @return amountOut Amount of asset i received (in 64.64 fixed-point)
/// @return amountIn LP size-metric redeemed (alpha * S)
function swapAmountsForBurn( function swapAmountsForBurn(
int128 kappa, uint256 nAssets,
int128 b,
int128[] memory qInternal, int128[] memory qInternal,
uint256 i, uint256 i,
int128 alpha int128 alpha
) internal pure returns (int128 amountIn, int128 amountOut) { ) internal pure returns (int128 amountOut, int128 amountIn) {
require(i < nAssets, "LMSR: idx");
require(alpha > int128(0) && alpha <= ONE, "LMSR: alpha"); require(alpha > int128(0) && alpha <= ONE, "LMSR: alpha");
// Compute size metric S for payout normalization; use provided b for curvature
int128 sizeMetric = _computeSizeMetric(qInternal); int128 sizeMetric = _computeSizeMetric(qInternal);
require(sizeMetric > int128(0), "LMSR: size metric zero"); require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
require(b > int128(0), "LMSR: b<=0"); require(b > int128(0), "LMSR: b<=0");
int128 invB = ABDKMath64x64.div(ONE, b); int128 invB = ABDKMath64x64.div(ONE, b);
uint256 n = qInternal.length; uint256 n = nAssets;
// Size metric and burned size (amountIn returned) // Size metric and burned size (amountIn returned)
int128 S = sizeMetric; int128 S = sizeMetric;
@@ -566,10 +595,10 @@ library LMSRStabilized {
} }
// Start totalOut with direct portion of asset i redeemed // Start totalOut with direct portion of asset i redeemed
amountOut = alpha.mul(qInternal[i]); int128 totalOut = alpha.mul(qInternal[i]);
// Track whether any non-zero contribution was produced // Track whether any non-zero contribution was produced
bool anyNonZero = (amountOut > int128(0)); bool anyNonZero = (totalOut > int128(0));
// For each asset j != i, swap the withdrawn a_j := alpha * q_j into i // For each asset j != i, swap the withdrawn a_j := alpha * q_j into i
for (uint256 j = 0; j < n; ) { for (uint256 j = 0; j < n; ) {
@@ -621,7 +650,7 @@ library LMSRStabilized {
// Update q_local: pool receives amountInUsed on asset j, and loses qLocal[i] // Update q_local: pool receives amountInUsed on asset j, and loses qLocal[i]
qLocal[j] = qLocal[j].add(amountInUsed); qLocal[j] = qLocal[j].add(amountInUsed);
// subtract capped output from qLocal[i] (becomes zero) // subtract capped output from qLocal[i] (becomes zero)
amountOut = amountOut.add(qLocal[i]); totalOut = totalOut.add(qLocal[i]);
qLocal[i] = int128(0); qLocal[i] = int128(0);
anyNonZero = true; anyNonZero = true;
unchecked { j++; } unchecked { j++; }
@@ -632,7 +661,7 @@ library LMSRStabilized {
// Update q_local accordingly: pool receives aj on j, and loses y on i // Update q_local accordingly: pool receives aj on j, and loses y on i
qLocal[j] = qLocal[j].add(aj); qLocal[j] = qLocal[j].add(aj);
qLocal[i] = qLocal[i].sub(y); qLocal[i] = qLocal[i].sub(y);
amountOut = amountOut.add(y); totalOut = totalOut.add(y);
anyNonZero = true; anyNonZero = true;
} }
} }
@@ -640,9 +669,12 @@ library LMSRStabilized {
} }
// If no asset contributed (totalOut == 0) treat as no-trade and revert // If no asset contributed (totalOut == 0) treat as no-trade and revert
if (!anyNonZero || amountOut <= int128(0)) { if (!anyNonZero || totalOut <= int128(0)) {
revert("LMSR: zero output"); revert("LMSR: zero output");
} }
amountOut = totalOut;
return (amountOut, amountIn);
} }
@@ -659,6 +691,7 @@ library LMSRStabilized {
int128 amountIn, int128 amountIn,
int128 amountOut int128 amountOut
) internal { ) internal {
require(i < s.nAssets && j < s.nAssets, "LMSR: idx");
require(amountIn > int128(0), "LMSR: amountIn <= 0"); require(amountIn > int128(0), "LMSR: amountIn <= 0");
require(amountOut > int128(0), "LMSR: amountOut <= 0"); require(amountOut > int128(0), "LMSR: amountOut <= 0");
@@ -673,33 +706,61 @@ library LMSRStabilized {
/// Updates the internal qInternal cache with the new balances /// Updates the internal qInternal cache with the new balances
/// @param newQInternal New asset quantities after mint/redeem (64.64 format) /// @param newQInternal New asset quantities after mint/redeem (64.64 format)
function updateForProportionalChange(State storage s, int128[] memory newQInternal) internal { function updateForProportionalChange(State storage s, int128[] memory newQInternal) internal {
require(newQInternal.length == s.nAssets, "LMSR: length mismatch");
// Compute new total for validation // Compute new total for validation
int128 newTotal = _computeSizeMetric(newQInternal); int128 newTotal = _computeSizeMetric(newQInternal);
require(newTotal > int128(0), "LMSR: new total zero"); require(newTotal > int128(0), "LMSR: new total zero");
// Update the cached qInternal with new values // Update the cached qInternal with new values
uint256 n = newQInternal.length; for (uint i = 0; i < s.nAssets; ) {
for (uint i = 0; i < n; ) {
s.qInternal[i] = newQInternal[i]; s.qInternal[i] = newQInternal[i];
unchecked { i++; } unchecked { i++; }
} }
} }
/// @notice Optional helper: recompute qInternal from reserves and explicit virtual offsets.
/// @dev This variant is useful if callers manage virtual offsets off-chain and want to preserve price neutrality
/// across proportional mints/burns by applying updated offsets alongside reserve changes.
/// @param newReservesInternal New reserves vector in 64.64 (converted from uint balances)
/// @param vOffsets Per-asset virtual offsets to apply (same length as nAssets)
function updateForProportionalChangeWithOffsets(
State storage s,
int128[] memory newReservesInternal,
int128[] memory vOffsets
) internal {
require(newReservesInternal.length == s.nAssets, "LMSR: length mismatch");
require(vOffsets.length == s.nAssets, "LMSR: v length mismatch");
int128[] memory combined = new int128[](s.nAssets);
for (uint i = 0; i < s.nAssets; ) {
combined[i] = newReservesInternal[i].add(vOffsets[i]);
unchecked { i++; }
}
int128 newTotal = _computeSizeMetric(combined);
require(newTotal > int128(0), "LMSR: new total zero");
for (uint i = 0; i < s.nAssets; ) {
s.qInternal[i] = combined[i];
unchecked { i++; }
}
}
/// @notice Price-share of asset i: exp(z_i) / Z (64.64) /// @notice Price-share of asset i: exp(z_i) / Z (64.64)
function priceShare(State storage s, uint256 i) internal view returns (int128) { function priceShare(State storage s, uint256 i) internal view returns (int128) {
return priceShare(s.kappa, s.qInternal, i); int128 b = _computeB(s);
return priceShare(b, s.qInternal, i);
} }
/// @notice Pure version: Price-share of asset i: exp(z_i) / Z (64.64) /// @notice Pure version: Price-share of asset i: exp(z_i) / Z (64.64)
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param i Index of asset /// @param i Index of asset
/// @return Price share in 64.64 fixed-point format /// @return Price share in 64.64 fixed-point format
function priceShare(int128 kappa, int128[] memory qInternal, uint256 i) internal pure returns (int128) { function priceShare(int128 b, int128[] memory qInternal, uint256 i) internal pure returns (int128) {
int128 sizeMetric = _computeSizeMetric(qInternal); require(b > int128(0), "LMSR: b<=0");
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
uint len = qInternal.length; uint len = qInternal.length;
require(len > 0, "LMSR: no assets"); require(len > 0, "LMSR: no assets");
@@ -757,20 +818,20 @@ library LMSRStabilized {
/// @notice Marginal price of `base` in terms of `quote` (p_quote / p_base) as Q64.64 /// @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. /// @dev Returns exp((q_quote - q_base) / b). Indices must be valid and b > 0.
function price(State storage s, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal view returns (int128) { function price(State storage s, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal view returns (int128) {
return price(s.kappa, s.qInternal, baseTokenIndex, quoteTokenIndex); int128 b = _computeB(s);
return price(s.nAssets, b, s.qInternal, baseTokenIndex, quoteTokenIndex);
} }
/// @notice Pure version: Marginal price of `base` in terms of `quote` (p_quote / p_base) as Q64.64 /// @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. /// @dev Returns exp((q_quote - q_base) / b). Indices must be valid and b > 0.
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param nAssets Number of assets in the pool
/// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param baseTokenIndex Index of base token /// @param baseTokenIndex Index of base token
/// @param quoteTokenIndex Index of quote token /// @param quoteTokenIndex Index of quote token
/// @return Price in 64.64 fixed-point format /// @return Price in 64.64 fixed-point format
function price(int128 kappa, int128[] memory qInternal, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal pure returns (int128) { function price(uint256 nAssets, int128 b, int128[] memory qInternal, uint256 baseTokenIndex, uint256 quoteTokenIndex) internal pure returns (int128) {
int128 sizeMetric = _computeSizeMetric(qInternal); require(baseTokenIndex < nAssets && quoteTokenIndex < nAssets, "LMSR: idx");
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
require(b > int128(0), "LMSR: b<=0"); require(b > int128(0), "LMSR: b<=0");
// Use reciprocal of b to avoid repeated divisions // Use reciprocal of b to avoid repeated divisions
@@ -783,24 +844,22 @@ library LMSRStabilized {
/// @notice Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64) /// @notice Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64)
/// @dev Computes: poolPrice_quote = (1 / S) * sum_j q_j * exp((q_j - q_quote) / b) /// @dev Computes: poolPrice_quote = (1 / S) * sum_j q_j * exp((q_j - q_quote) / b)
function poolPrice(State storage s, uint256 quoteTokenIndex) internal view returns (int128) { function poolPrice(State storage s, uint256 quoteTokenIndex) internal view returns (int128) {
return poolPrice(s.kappa, s.qInternal, quoteTokenIndex); int128 b = _computeB(s);
return poolPrice(s.nAssets, b, s.qInternal, quoteTokenIndex);
} }
/// @notice Pure version: Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64) /// @notice Pure version: Price of one unit of the LP size-metric (S = sum q_i) denominated in `quote` asset (Q64.64)
/// @dev Computes: poolPrice_quote = (1 / S) * sum_j q_j * exp((q_j - q_quote) / b) /// @dev Computes: poolPrice_quote = (1 / S) * sum_j q_j * exp((q_j - q_quote) / b)
/// @param kappa Liquidity parameter κ (64.64 fixed point) /// @param nAssets Number of assets in the pool
/// @param b Liquidity parameter κ (64.64 fixed point)
/// @param qInternal Cached internal balances in 64.64 fixed-point format /// @param qInternal Cached internal balances in 64.64 fixed-point format
/// @param quoteTokenIndex Index of quote token /// @param quoteTokenIndex Index of quote token
/// @return Pool price in 64.64 fixed-point format /// @return Pool price in 64.64 fixed-point format
function poolPrice(int128 kappa, int128[] memory qInternal, uint256 quoteTokenIndex) internal pure returns (int128) { function poolPrice(uint256 nAssets, int128 b, int128[] memory qInternal, uint256 quoteTokenIndex) internal pure returns (int128) {
// Compute b and ensure positivity require(quoteTokenIndex < nAssets, "LMSR: idx");
int128 sizeMetric = _computeSizeMetric(qInternal); // Ensure positivity and compute total size metric S = sum q_i
require(sizeMetric > int128(0), "LMSR: size metric zero");
int128 b = kappa.mul(sizeMetric);
require(b > int128(0), "LMSR: b<=0"); require(b > int128(0), "LMSR: b<=0");
int128 S = _computeSizeMetric(qInternal);
// Compute total size metric S = sum q_i
int128 S = sizeMetric;
require(S > int128(0), "LMSR: size zero"); require(S > int128(0), "LMSR: size zero");
// Precompute reciprocal of b // Precompute reciprocal of b
@@ -808,7 +867,7 @@ library LMSRStabilized {
// Accumulate weighted exponentials: sum_j q_j * exp((q_j - q_quote) / b) // Accumulate weighted exponentials: sum_j q_j * exp((q_j - q_quote) / b)
int128 acc = int128(0); int128 acc = int128(0);
uint256 n = qInternal.length; uint256 n = nAssets;
for (uint256 j = 0; j < n; ) { for (uint256 j = 0; j < n; ) {
// factor = exp((q_j - q_quote) / b) // factor = exp((q_j - q_quote) / b)
int128 factor = _exp(qInternal[j].sub(qInternal[quoteTokenIndex]).mul(invB)); int128 factor = _exp(qInternal[j].sub(qInternal[quoteTokenIndex]).mul(invB));
@@ -826,9 +885,8 @@ library LMSRStabilized {
Slippage -> b computation & resize-triggered rescale Slippage -> b computation & resize-triggered rescale
-------------------- */ -------------------- */
/// @notice Internal helper to compute kappa from slippage parameters. /// @notice Internal helper to compute kappa from slippage parameters. (Deprecated in favor of computeBFromSlippage)
/// @dev Returns κ in Q64.64. Implemented as internal so callers within the library can use it /// @dev Returns κ in Q64.64 for reference. Prefer computing b directly via computeBFromSlippage.
/// without resorting to external calls.
function computeKappaFromSlippage( function computeKappaFromSlippage(
uint256 nAssets, uint256 nAssets,
int128 tradeFrac, int128 tradeFrac,
@@ -876,7 +934,57 @@ library LMSRStabilized {
return kappa; return kappa;
} }
/// @notice Legacy-compatible init: compute kappa from slippage parameters and delegate to kappa-based init. /// @notice Compute fixed b from a target slippage profile.
/// @dev For a trade of fraction f of the size metric S, targeting slippage s, we have y := -ln(E)/f with
/// E = (1 - s*(n-1)) / (1 + s) and b = S / y.
function computeBFromSlippage(
uint256 nAssets,
int128 sizeMetricS,
int128 tradeFrac,
int128 targetSlippage
) internal pure returns (int128) {
require(nAssets > 1, "LMSR: n>1 required");
require(sizeMetricS > int128(0), "LMSR: S<=0");
// f must be in (0,1)
int128 f = tradeFrac;
require(f > int128(0), "LMSR: f=0");
require(f < ONE, "LMSR: f>=1");
int128 onePlusS = ONE.add(targetSlippage);
int128 n64 = ABDKMath64x64.fromUInt(nAssets);
int128 nMinus1_64 = ABDKMath64x64.fromUInt(nAssets - 1);
// If 1 + s >= n then equal-inventories closed-form applies
bool useEqual = (onePlusS >= n64);
// E candidate used in deriving y = -ln(E)/f (same expression in both branches)
int128 numerator = ONE.sub(targetSlippage.mul(nMinus1_64)); // 1 - s*(n-1)
int128 denominator = onePlusS; // 1 + s
if (useEqual) {
// Guard numerator to ensure E in (0,1)
require(numerator > int128(0), "LMSR: s too large for n");
} else {
require(numerator > int128(0), "LMSR: bad slippage or n");
}
int128 E_candidate = numerator.div(denominator);
require(E_candidate > int128(0) && E_candidate < ONE, "LMSR: bad E ratio");
// y = -ln(E) / f
int128 lnE = _ln(E_candidate);
int128 y = lnE.neg().div(f);
require(y > int128(0), "LMSR: y<=0");
// b = S / y
int128 b = ABDKMath64x64.div(sizeMetricS, y);
require(b > int128(0), "LMSR: b<=0");
return b;
}
/// @notice Legacy-compatible init: compute fixed b from slippage parameters and delegate to fixed-b init.
/// @dev Provides backward compatibility for callers that still use the (q, tradeFrac, targetSlippage) init signature. /// @dev Provides backward compatibility for callers that still use the (q, tradeFrac, targetSlippage) init signature.
function init( function init(
State storage s, State storage s,
@@ -884,10 +992,11 @@ library LMSRStabilized {
int128 tradeFrac, int128 tradeFrac,
int128 targetSlippage int128 targetSlippage
) internal { ) internal {
// compute kappa using the internal helper // compute b directly from the current size metric and the slippage profile
int128 kappa = computeKappaFromSlippage(initialQInternal.length, tradeFrac, targetSlippage); int128 S = _computeSizeMetric(initialQInternal);
// forward to the new kappa-based init int128 b = computeBFromSlippage(initialQInternal.length, S, tradeFrac, targetSlippage);
init(s, initialQInternal, kappa); // forward to the fixed-b init
init(s, initialQInternal, b);
} }
@@ -895,12 +1004,13 @@ library LMSRStabilized {
/// This resets the state so the pool can be re-initialized by init(...) on next mint. /// This resets the state so the pool can be re-initialized by init(...) on next mint.
function deinit(State storage s) internal { function deinit(State storage s) internal {
// Reset core state // Reset core state
s.kappa = int128(0); s.nAssets = 0;
s.bFixed = int128(0);
// Clear qInternal array // Clear qInternal array
delete s.qInternal; delete s.qInternal;
// Note: init(...) will recompute kappa and nAssets on first mint. // Note: initWithFixedB(...) will set b and nAssets on first mint.
} }
/// @notice Compute M (shift) and Z (sum of exponentials) dynamically /// @notice Compute M (shift) and Z (sum of exponentials) dynamically
@@ -978,9 +1088,8 @@ library LMSRStabilized {
/// @notice Compute b from kappa and current asset quantities /// @notice Compute b from kappa and current asset quantities
function _computeB(State storage s) internal view returns (int128) { function _computeB(State storage s) internal view returns (int128) {
int128 sizeMetric = _computeSizeMetric(s.qInternal); // require(s.bFixed > int128(0), "LMSR: b not set");
require(sizeMetric > int128(0), "LMSR: size metric zero"); return s.bFixed;
return s.kappa.mul(sizeMetric);
} }
} }

View File

@@ -35,11 +35,10 @@ library LMSRStabilizedBalancedPair {
int128 limitPrice int128 limitPrice
) internal view returns (int128 amountIn, int128 amountOut) { ) internal view returns (int128 amountIn, int128 amountOut) {
// Quick index check // Quick index check
uint256 nAssets = s.qInternal.length; require(i < s.nAssets && j < s.nAssets, "LMSR: idx");
require(i < nAssets && j < nAssets, "LMSR: idx");
// If not exactly a two-asset pool, fall back to the general routine. // If not exactly a two-asset pool, fall back to the general routine.
if (nAssets != 2) { if (s.nAssets != 2) {
return LMSRStabilized.swapAmountsForExactInput(s, i, j, a, limitPrice); return LMSRStabilized.swapAmountsForExactInput(s, i, j, a, limitPrice);
} }

View File

@@ -81,14 +81,15 @@ contract PartyPlanner is OwnableExternal, IPartyPlanner {
protocolFeeAddress = protocolFeeAddress_; protocolFeeAddress = protocolFeeAddress_;
} }
/// Main newPool variant: accepts kappa directly (preferred) and a per-asset fee vector. /// Main newPool variant: accepts kappa directly (preferred).
function newPool( function newPool(
// Pool constructor args // Pool constructor args
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
IERC20[] memory tokens_, IERC20[] memory tokens_,
uint256[] memory bases_,
int128 kappa_, int128 kappa_,
uint256[] memory swapFeesPpm_, uint256 swapFeePpm_,
uint256 flashFeePpm_, uint256 flashFeePpm_,
bool stable_, bool stable_,
// Initial deposit information // Initial deposit information
@@ -107,9 +108,6 @@ contract PartyPlanner is OwnableExternal, IPartyPlanner {
// Validate kappa > 0 (Q64.64) // Validate kappa > 0 (Q64.64)
require(kappa_ > int128(0), "Planner: kappa must be > 0"); require(kappa_ > int128(0), "Planner: kappa must be > 0");
// Validate fees vector length matches number of tokens
require(swapFeesPpm_.length == tokens_.length, "Planner: fees and tokens length mismatch");
// Create a new PartyPool instance (kappa-based constructor) // Create a new PartyPool instance (kappa-based constructor)
IPartyPoolDeployer deployer = stable_ && tokens_.length == 2 ? BALANCED_PAIR_DEPLOYER : NORMAL_POOL_DEPLOYER; IPartyPoolDeployer deployer = stable_ && tokens_.length == 2 ? BALANCED_PAIR_DEPLOYER : NORMAL_POOL_DEPLOYER;
pool = deployer.deploy( pool = deployer.deploy(
@@ -117,8 +115,9 @@ contract PartyPlanner is OwnableExternal, IPartyPlanner {
name_, name_,
symbol_, symbol_,
tokens_, tokens_,
bases_,
kappa_, kappa_,
swapFeesPpm_, swapFeePpm_,
flashFeePpm_, flashFeePpm_,
PROTOCOL_FEE_PPM, PROTOCOL_FEE_PPM,
protocolFeeAddress, protocolFeeAddress,
@@ -158,48 +157,6 @@ contract PartyPlanner is OwnableExternal, IPartyPlanner {
lpAmount = pool.initialMint(receiver, initialLpAmount); lpAmount = pool.initialMint(receiver, initialLpAmount);
} }
/// Convenience overload: legacy single-fee signature — repeat the scalar for every asset and delegate.
function newPool(
// Pool constructor args (legacy single-fee)
string memory name_,
string memory symbol_,
IERC20[] memory tokens_,
int128 kappa_,
uint256 swapFeePpm_,
uint256 flashFeePpm_,
bool stable_,
// Initial deposit information
address payer,
address receiver,
uint256[] memory initialDeposits,
uint256 initialLpAmount,
uint256 deadline
) public onlyOwner returns (IPartyPool pool, uint256 lpAmount) {
// Build per-asset fee vector by repeating the scalar swapFeePpm_
uint256[] memory feesArr = new uint256[](tokens_.length);
for (uint256 i = 0; i < tokens_.length; i++) {
// We divide by two, because the new per-asset fee semantics charges both the in-asset fee and
// out-asset fee. This should be a square-root for exactness.
feesArr[i] = swapFeePpm_ / 2;
}
// Delegate to the vector-based newPool variant
return newPool(
name_,
symbol_,
tokens_,
kappa_,
feesArr,
flashFeePpm_,
stable_,
payer,
receiver,
initialDeposits,
initialLpAmount,
deadline
);
}
// NOTE that the slippage target is only exactly achieved in completely balanced pools where all assets are // NOTE that the slippage target is only exactly achieved in completely balanced pools where all assets are
// priced the same. This target is actually a minimum slippage that the pool imposes on traders, and the actual // priced the same. This target is actually a minimum slippage that the pool imposes on traders, and the actual
// slippage cost can be multiples bigger in practice due to pool inventory imbalances. // slippage cost can be multiples bigger in practice due to pool inventory imbalances.
@@ -208,6 +165,7 @@ contract PartyPlanner is OwnableExternal, IPartyPlanner {
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
IERC20[] memory tokens_, IERC20[] memory tokens_,
uint256[] memory bases_,
int128 tradeFrac_, int128 tradeFrac_,
int128 targetSlippage_, int128 targetSlippage_,
uint256 swapFeePpm_, uint256 swapFeePpm_,
@@ -232,6 +190,7 @@ contract PartyPlanner is OwnableExternal, IPartyPlanner {
name_, name_,
symbol_, symbol_,
tokens_, tokens_,
bases_,
computedKappa, computedKappa,
swapFeePpm_, swapFeePpm_,
flashFeePpm_, flashFeePpm_,

View File

@@ -19,7 +19,7 @@ import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/uti
import {IERC3156FlashLender} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol"; import {IERC3156FlashLender} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol";
import {NativeWrapper} from "./NativeWrapper.sol"; import {NativeWrapper} from "./NativeWrapper.sol";
import {OwnableExternal} from "./OwnableExternal.sol"; import {OwnableExternal} from "./OwnableExternal.sol";
import {IPartyInfo} from "./IPartyInfo.sol"; import {IPartyPoolViewer} from "./IPartyPoolViewer.sol";
/// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token /// @title PartyPool - LMSR-backed multi-asset pool with LP ERC20 token
/// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model. /// @notice A multi-asset liquidity pool backed by the LMSRStabilized pricing model.
@@ -48,17 +48,13 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
function wrapperToken() external view returns (NativeWrapper) { return WRAPPER_TOKEN; } function wrapperToken() external view returns (NativeWrapper) { return WRAPPER_TOKEN; }
/// @notice Liquidity parameter κ (Q64.64) used by the LMSR kernel: b = κ * S(q) /// @notice Fixed LMSR curvature parameter b (Q64.64)
/// @dev Pool is constructed with a fixed κ. Clients that previously passed tradeFrac/targetSlippage int128 private immutable B_FIXED;
/// should use LMSRStabilized.computeKappaFromSlippage(...) to derive κ and pass it here. function bFixed() external view returns (int128) { return B_FIXED; }
int128 private immutable KAPPA; // kappa in Q64.64
function kappa() external view returns (int128) { return KAPPA; }
/// @notice Per-asset swap fees in ppm. /// @notice Per-swap fee in parts-per-million (ppm). Fee is taken from input amounts before LMSR computations.
function fees() external view returns (uint256[] memory) { return _fees; } uint256 private immutable SWAP_FEE_PPM;
function swapFeePpm() external view returns (uint256) { return SWAP_FEE_PPM; }
/// @notice Effective combined fee in ppm for (i as input, j as output)
function fee(uint256 i, uint256 j) external view returns (uint256) { return _pairFeePpmView(i,j); }
/// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts. /// @notice Flash-loan fee in parts-per-million (ppm) applied to flash borrow amounts.
uint256 private immutable FLASH_FEE_PPM; uint256 private immutable FLASH_FEE_PPM;
@@ -94,7 +90,6 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
/// @inheritdoc IPartyPool /// @inheritdoc IPartyPool
function denominators() external view returns (uint256[] memory) { return _bases; } function denominators() external view returns (uint256[] memory) { return _bases; }
/// @inheritdoc IPartyPool
function LMSR() external view returns (LMSRStabilized.State memory) { return _lmsr; } function LMSR() external view returns (LMSRStabilized.State memory) { return _lmsr; }
@@ -102,8 +97,9 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
/// @param name_ LP token name /// @param name_ LP token name
/// @param symbol_ LP token symbol /// @param symbol_ LP token symbol
/// @param tokens_ token addresses (n) /// @param tokens_ token addresses (n)
/// @param kappa_ liquidity parameter κ (Q64.64) used to derive b = κ * S(q) /// @param bases_ scaling _bases for each token (n) - used when converting to/from internal 64.64 amounts
/// @param fees_ per-asset swap fees in ppm (length must equal tokens_.length) /// @param bFixed_ fixed LMSR curvature b (Q64.64)
/// @param swapFeePpm_ fee in parts-per-million, taken from swap input amounts before LMSR calculations
/// @param flashFeePpm_ fee in parts-per-million, taken for flash loans /// @param flashFeePpm_ fee in parts-per-million, taken for flash loans
/// @param swapImpl_ address of the SwapMint implementation contract /// @param swapImpl_ address of the SwapMint implementation contract
/// @param mintImpl_ address of the Mint implementation contract /// @param mintImpl_ address of the Mint implementation contract
@@ -112,8 +108,9 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
IERC20[] memory tokens_, IERC20[] memory tokens_,
int128 kappa_, uint256[] memory bases_,
uint256[] memory fees_, int128 bFixed_,
uint256 swapFeePpm_,
uint256 flashFeePpm_, uint256 flashFeePpm_,
uint256 protocolFeePpm_, uint256 protocolFeePpm_,
address protocolFeeAddress_, address protocolFeeAddress_,
@@ -127,19 +124,15 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
{ {
require(owner_ != address(0)); require(owner_ != address(0));
require(tokens_.length > 1, "Pool: need >1 asset"); require(tokens_.length > 1, "Pool: need >1 asset");
require(tokens_.length == bases_.length, "Pool: lengths mismatch");
_tokens = tokens_; _tokens = tokens_;
KAPPA = kappa_; _bases = bases_;
require(fees_.length == tokens_.length, "Pool: fees length"); B_FIXED = bFixed_;
// validate ppm bounds and assign require(swapFeePpm_ < 1_000_000, "Pool: fee >= ppm");
_fees = new uint256[](fees_.length); SWAP_FEE_PPM = swapFeePpm_;
for (uint256 i = 0; i < fees_.length; i++) { require(flashFeePpm_ < 1_000_000, "Pool: flash fee >= ppm");
// Cap all fees at 1%
require(fees_[i] < 10_000, "Pool: fee >= 1%");
_fees[i] = fees_[i];
}
require(flashFeePpm_ < 10_000, "Pool: flash fee >= 1%");
FLASH_FEE_PPM = flashFeePpm_; FLASH_FEE_PPM = flashFeePpm_;
require(protocolFeePpm_ < 400_000, "Pool: protocol fee >= 40%"); require(protocolFeePpm_ < 1_000_000, "Pool: protocol fee >= ppm");
// If the protocolFeePpm_ is set, then also require the fee address to be nonzero // If the protocolFeePpm_ is set, then also require the fee address to be nonzero
require(protocolFeePpm_ == 0 || protocolFeeAddress_ != address(0)); require(protocolFeePpm_ == 0 || protocolFeeAddress_ != address(0));
PROTOCOL_FEE_PPM = protocolFeePpm_; PROTOCOL_FEE_PPM = protocolFeePpm_;
@@ -149,15 +142,15 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 n = tokens_.length; uint256 n = tokens_.length;
// Initialize LMSR state nAssets; full init occurs on first mint when quantities are known.
_lmsr.nAssets = n;
// Initialize token address to index mapping // Initialize token address to index mapping
for (uint i = 0; i < n;) { for (uint i = 0; i < n;) {
_tokenAddressToIndexPlusOne[tokens_[i]] = i + 1; _tokenAddressToIndexPlusOne[tokens_[i]] = i + 1;
unchecked {i++;} unchecked {i++;}
} }
// Allocate denominators (bases) to be computed during initialMint from initial deposits
_bases = new uint256[](n);
// Initialize caches to zero and protocol ledger // Initialize caches to zero and protocol ledger
_cachedUintBalances = new uint256[](n); _cachedUintBalances = new uint256[](n);
_protocolFeesOwed = new uint256[](n); _protocolFeesOwed = new uint256[](n);
@@ -174,11 +167,9 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
/// @notice If a security problem is found, the vault owner may call this function to permanently disable swap and /// @notice If a security problem is found, the vault owner may call this function to permanently disable swap and
/// mint functionality, leaving only burns (withdrawals) working. /// mint functionality, leaving only burns (withdrawals) working.
function kill() external onlyOwner { function kill() external onlyOwner {
if( !_killed ) {
_killed = true; _killed = true;
emit Killed(); emit Killed();
} }
}
/* ---------------------- /* ----------------------
Initialization / Mint / Burn (LP token managed) Initialization / Mint / Burn (LP token managed)
@@ -191,7 +182,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
PartyPoolMintImpl.initialMint.selector, PartyPoolMintImpl.initialMint.selector,
receiver, receiver,
lpTokens, lpTokens,
KAPPA B_FIXED
); );
bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data); bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data);
return abi.decode(result, (uint256)); return abi.decode(result, (uint256));
@@ -240,15 +231,14 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 outputTokenIndex, uint256 outputTokenIndex,
uint256 maxAmountIn, uint256 maxAmountIn,
int128 limitPrice int128 limitPrice
) external view returns (uint256 amountIn, uint256 amountOut, uint256 inFee) { ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
(uint256 grossIn, uint256 outUint,,,, uint256 feeUint) = _quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, _pairFeePpmView(inputTokenIndex, outputTokenIndex)); (uint256 grossIn, uint256 outUint,,,, uint256 feeUint) = _quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
return (grossIn, outUint, feeUint); return (grossIn, outUint, feeUint);
} }
/// @inheritdoc IPartyPool /// @inheritdoc IPartyPool
function swap( function swap(
address payer, address payer,
bytes4 selector,
address receiver, address receiver,
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
@@ -256,29 +246,19 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
int128 limitPrice, int128 limitPrice,
uint256 deadline, uint256 deadline,
bool unwrap bool unwrap
) external payable native nonReentrant killable returns (uint256 amountIn, uint256 amountOut, uint256 inFee) { ) external payable native nonReentrant killable returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
require(deadline == 0 || block.timestamp <= deadline, "swap: deadline exceeded"); require(deadline == 0 || block.timestamp <= deadline, "swap: deadline exceeded");
// Compute amounts using the same path as views // Compute amounts using the same path as views
(uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalUsed, int128 amountOutInternal, , uint256 feeUint) = (uint256 totalTransferAmount, uint256 amountOutUint, int128 amountInInternalUsed, int128 amountOutInternal, , uint256 feeUint) =
_quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice, _pairFeePpm(inputTokenIndex, outputTokenIndex)); _quoteSwapExactIn(inputTokenIndex, outputTokenIndex, maxAmountIn, limitPrice);
// Cache token references for fewer SLOADs // Cache token references for fewer SLOADs
IERC20 tokenIn = _tokens[inputTokenIndex]; IERC20 tokenIn = _tokens[inputTokenIndex];
IERC20 tokenOut = _tokens[outputTokenIndex]; IERC20 tokenOut = _tokens[outputTokenIndex];
if ( selector == bytes4(0) ) // Transfer _tokens in via centralized helper
// Regular ERC20 permit of the pool to move the tokens
_receiveTokenFrom(payer, tokenIn, totalTransferAmount); _receiveTokenFrom(payer, tokenIn, totalTransferAmount);
else {
// Callback-style funding mechanism
uint256 startingBalance = tokenIn.balanceOf(address(this));
bytes memory data = abi.encodeWithSelector(selector, tokenIn, totalTransferAmount);
// Invoke the payer callback; no return value expected (reverts on failure)
Address.functionCall(payer, data);
uint256 endingBalance = tokenIn.balanceOf(address(this));
require(endingBalance-startingBalance == totalTransferAmount, 'Insufficient funds');
}
// Compute on-chain balances as: onchain = cached + owed (+/- transfer) // Compute on-chain balances as: onchain = cached + owed (+/- transfer)
uint256 balIAfter = _cachedUintBalances[inputTokenIndex] + _protocolFeesOwed[inputTokenIndex] + totalTransferAmount; uint256 balIAfter = _cachedUintBalances[inputTokenIndex] + _protocolFeesOwed[inputTokenIndex] + totalTransferAmount;
@@ -321,9 +301,10 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
uint256 maxAmountIn, uint256 maxAmountIn,
int128 limitPrice, int128 limitPrice
uint256 feePpm )
) internal view internal
view
returns ( returns (
uint256 grossIn, uint256 grossIn,
uint256 amountOutUint, uint256 amountOutUint,
@@ -334,7 +315,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
) )
{ {
// Estimate max net input (fee on gross rounded up, then subtract) // Estimate max net input (fee on gross rounded up, then subtract)
(, uint256 netUintForSwap) = _computeFee(maxAmountIn, feePpm); (, uint256 netUintForSwap) = _computeFee(maxAmountIn, SWAP_FEE_PPM);
// Convert to internal (floor) // Convert to internal (floor)
int128 deltaInternalI = _uintToInternalFloor(netUintForSwap, _bases[inputTokenIndex]); int128 deltaInternalI = _uintToInternalFloor(netUintForSwap, _bases[inputTokenIndex]);
@@ -350,8 +331,8 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
// Compute gross transfer including fee on the used input (ceil) // Compute gross transfer including fee on the used input (ceil)
feeUint = 0; feeUint = 0;
grossIn = amountInUintNoFee; grossIn = amountInUintNoFee;
if (feePpm > 0) { if (SWAP_FEE_PPM > 0) {
feeUint = _ceilFee(amountInUintNoFee, feePpm); feeUint = _ceilFee(amountInUintNoFee, SWAP_FEE_PPM);
grossIn += feeUint; grossIn += feeUint;
} }
@@ -372,7 +353,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
int128 limitPrice, int128 limitPrice,
uint256 deadline, uint256 deadline,
bool unwrap bool unwrap
) external payable returns (uint256 amountInUsed, uint256 amountOut, uint256 inFee) { ) external payable returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
bytes memory data = abi.encodeWithSelector( bytes memory data = abi.encodeWithSelector(
PartyPoolSwapImpl.swapToLimit.selector, PartyPoolSwapImpl.swapToLimit.selector,
payer, payer,
@@ -382,7 +363,7 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
limitPrice, limitPrice,
deadline, deadline,
unwrap, unwrap,
_pairFeePpm(inputTokenIndex, outputTokenIndex), SWAP_FEE_PPM,
PROTOCOL_FEE_PPM PROTOCOL_FEE_PPM
); );
bytes memory result = Address.functionDelegateCall(address(SWAP_IMPL), data); bytes memory result = Address.functionDelegateCall(address(SWAP_IMPL), data);
@@ -397,14 +378,14 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
/// @param inputTokenIndex index of the input token /// @param inputTokenIndex index of the input token
/// @param maxAmountIn maximum uint token input (inclusive of fee) /// @param maxAmountIn maximum uint token input (inclusive of fee)
/// @param deadline optional deadline /// @param deadline optional deadline
/// @return amountInUsed actual input used (uint256), lpMinted actual LP minted (uint256), inFee fee taken from the input (uint256) /// @return lpMinted actual LP minted (uint)
function swapMint( function swapMint(
address payer, address payer,
address receiver, address receiver,
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 maxAmountIn, uint256 maxAmountIn,
uint256 deadline uint256 deadline
) external payable returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee) { ) external payable returns (uint256 lpMinted) {
bytes memory data = abi.encodeWithSelector( bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.swapMint.selector, PartyPoolMintImpl.swapMint.selector,
payer, payer,
@@ -412,70 +393,103 @@ contract PartyPool is PartyPoolBase, OwnableExternal, ERC20External, IPartyPool
inputTokenIndex, inputTokenIndex,
maxAmountIn, maxAmountIn,
deadline, deadline,
_assetFeePpm(inputTokenIndex), SWAP_FEE_PPM,
PROTOCOL_FEE_PPM PROTOCOL_FEE_PPM
); );
bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data); bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data);
return abi.decode(result, (uint256, uint256, uint256)); return abi.decode(result, (uint256));
} }
/// @inheritdoc IPartyPool /// @notice Burn LP _tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
/// @dev This function forwards the call to the burnSwap implementation via delegatecall
/// @param payer who burns LP _tokens
/// @param receiver who receives the single asset
/// @param lpAmount amount of LP _tokens to burn
/// @param inputTokenIndex index of target asset to receive
/// @param deadline optional deadline
/// @return amountOutUint uint amount of asset i sent to receiver
function burnSwap( function burnSwap(
address payer, address payer,
address receiver, address receiver,
uint256 lpAmount, uint256 lpAmount,
uint256 outputTokenIndex, uint256 inputTokenIndex,
uint256 deadline, uint256 deadline,
bool unwrap bool unwrap
) external returns (uint256 amountOut, uint256 outFee) { ) external returns (uint256 amountOutUint) {
bytes memory data = abi.encodeWithSelector( bytes memory data = abi.encodeWithSelector(
PartyPoolMintImpl.burnSwap.selector, PartyPoolMintImpl.burnSwap.selector,
payer, payer,
receiver, receiver,
lpAmount, lpAmount,
outputTokenIndex, inputTokenIndex,
deadline, deadline,
unwrap, unwrap,
_assetFeePpm(outputTokenIndex), SWAP_FEE_PPM,
PROTOCOL_FEE_PPM PROTOCOL_FEE_PPM
); );
bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data); bytes memory result = Address.functionDelegateCall(address(MINT_IMPL), data);
return abi.decode(result, (uint256,uint256)); return abi.decode(result, (uint256));
} }
/// @inheritdoc IPartyPool bytes32 internal constant FLASH_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
/**
* @dev Loan `amount` _tokens to `receiver`, and takes it back plus a `flashFee` after the callback.
* @param receiver The contract receiving the _tokens, needs to implement the `onFlashLoan(address user, uint256 amount, uint256 fee, bytes calldata)` interface.
* @param tokenAddr The loan currency.
* @param amount The amount of _tokens lent.
* @param data A data parameter to be passed on to the `receiver` for any custom use.
*/
function flashLoan( function flashLoan(
IERC3156FlashBorrower receiver, IERC3156FlashBorrower receiver,
address tokenAddr, address tokenAddr,
uint256 amount, uint256 amount,
bytes calldata data bytes calldata data
) external returns (bool) ) external nonReentrant killable returns (bool)
{ {
bytes memory payload = abi.encodeWithSelector( IERC20 token = IERC20(tokenAddr);
PartyPoolSwapImpl.flashLoan.selector, require(amount <= token.balanceOf(address(this)));
receiver, uint256 tokenIndex = _tokenAddressToIndexPlusOne[token];
tokenAddr, require(tokenIndex != 0, 'flash: token not in pool');
amount, tokenIndex -= 1;
data, (uint256 fee, ) = _computeFee(amount, FLASH_FEE_PPM);
FLASH_FEE_PPM,
PROTOCOL_FEE_PPM // Compute protocol share of flash fee
); uint256 protoShare = 0;
bytes memory result = Address.functionDelegateCall(address(SWAP_IMPL), payload); if (PROTOCOL_FEE_PPM > 0 && fee > 0) {
return abi.decode(result, (bool)); protoShare = (fee * PROTOCOL_FEE_PPM) / 1_000_000; // floor
if (protoShare > 0) {
_protocolFeesOwed[tokenIndex] += protoShare;
}
}
_sendTokenTo(token, address(receiver), amount, false);
require(receiver.onFlashLoan(msg.sender, address(token), amount, fee, data) == FLASH_CALLBACK_SUCCESS);
_receiveTokenFrom(address(receiver), token, amount + fee);
// Update cached balance for the borrowed token
uint256 balAfter = token.balanceOf(address(this));
// Inline _recordCachedBalance logic
require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed");
_cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex];
emit Flash(msg.sender, receiver, token, amount, fee-protoShare, protoShare);
return true;
} }
/// @notice Transfer all protocol fees to the configured protocolFeeAddress and zero the ledger. /// @notice Transfer all protocol fees to the configured protocolFeeAddress and zero the ledger.
/// @dev Anyone can call; must have protocolFeeAddress != address(0) to be operational. /// @dev Anyone can call; must have protocolFeeAddress != address(0) to be operational.
function collectProtocolFees() external { function collectProtocolFees() external nonReentrant {
bytes memory data = abi.encodeWithSelector( bytes memory data = abi.encodeWithSelector(
PartyPoolSwapImpl.collectProtocolFees.selector, PartyPoolSwapImpl.collectProtocolFees.selector,
protocolFeeAddress protocolFeeAddress
); );
Address.functionDelegateCall(address(SWAP_IMPL), data); Address.functionDelegateCall(address(MINT_IMPL), data);
} }

View File

@@ -15,8 +15,9 @@ contract PartyPoolBalancedPair is PartyPool {
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
IERC20[] memory tokens_, IERC20[] memory tokens_,
uint256[] memory bases_,
int128 kappa_, int128 kappa_,
uint256[] memory fees_, uint256 swapFeePpm_,
uint256 flashFeePpm_, uint256 flashFeePpm_,
uint256 protocolFeePpm_, // NEW: protocol share of fees (ppm) uint256 protocolFeePpm_, // NEW: protocol share of fees (ppm)
address protocolFeeAddress_, // NEW: recipient for collected protocol tokens address protocolFeeAddress_, // NEW: recipient for collected protocol tokens
@@ -24,7 +25,7 @@ contract PartyPoolBalancedPair is PartyPool {
PartyPoolSwapImpl swapMintImpl_, PartyPoolSwapImpl swapMintImpl_,
PartyPoolMintImpl mintImpl_ PartyPoolMintImpl mintImpl_
) )
PartyPool(owner_, name_, symbol_, tokens_, kappa_, fees_, flashFeePpm_, protocolFeePpm_, protocolFeeAddress_, wrapperToken_, swapMintImpl_, mintImpl_) PartyPool(owner_, name_, symbol_, tokens_, bases_, kappa_, swapFeePpm_, flashFeePpm_, protocolFeePpm_, protocolFeeAddress_, wrapperToken_, swapMintImpl_, mintImpl_)
{} {}
function _swapAmountsForExactInput(uint256 i, uint256 j, int128 a, int128 limitPrice) internal virtual override view function _swapAmountsForExactInput(uint256 i, uint256 j, int128 a, int128 limitPrice) internal virtual override view

View File

@@ -1,15 +1,15 @@
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30; pragma solidity ^0.8.30;
import "./NativeWrapper.sol";
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol"; import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {ERC20Internal} from "./ERC20Internal.sol"; import {ERC20Internal} from "./ERC20Internal.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {LMSRStabilized} from "./LMSRStabilized.sol"; import {LMSRStabilized} from "./LMSRStabilized.sol";
import {NativeWrapper} from "./NativeWrapper.sol";
import {OwnableInternal} from "./OwnableInternal.sol";
import {PartyPoolHelpers} from "./PartyPoolHelpers.sol"; import {PartyPoolHelpers} from "./PartyPoolHelpers.sol";
import {ReentrancyGuard} from "../lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol";
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {OwnableInternal} from "./OwnableInternal.sol";
/// @notice Abstract base contract that contains storage and internal helpers only. /// @notice Abstract base contract that contains storage and internal helpers only.
/// No external/public functions here. /// No external/public functions here.
@@ -24,10 +24,6 @@ abstract contract PartyPoolBase is OwnableInternal, ERC20Internal, ReentrancyGua
WRAPPER_TOKEN = wrapper_; WRAPPER_TOKEN = wrapper_;
} }
/// @notice Per-asset swap fees in ppm. Fees are applied on input for swaps; see helpers for composition rules.
uint256[] internal _fees;
mapping( uint256 => uint256 ) internal _pairFees;
// //
// Internal state // Internal state
// //
@@ -82,36 +78,6 @@ abstract contract PartyPoolBase is OwnableInternal, ERC20Internal, ReentrancyGua
Conversion & fee helpers (internal) Conversion & fee helpers (internal)
---------------------- */ ---------------------- */
// Per-asset fee getters and composition
function _assetFeePpm(uint256 i) internal view returns (uint256) {
if (_fees.length == 0) return 0;
return _fees[i];
}
// Effective pair fee: 1 - (1-fi)(1-fj) in ppm, rounding in favor of the pool, and guarding
// overflows by using 1e6 ppm base.
// We implement this as: ceil( fi + fj - (fi*fj)/1e6 ) for the real-valued expression.
// For integer arithmetic with fi,fj in ppm this is equal to: fi + fj - floor( (fi*fj)/1e6 ).
// So we compute prod = fi * fj, prodDiv = prod / 1e6 (floor), and return fi + fj - prodDiv.
function _pairFeePpmView(uint256 i, uint256 j) internal view returns (uint256) {
uint256 fi = _fees[i];
uint256 fj = _fees[j];
// multiplicative combination, while mathematically correct, is more confusing to users
// return fi + fj - fi * fj / 1_000_000;
// additive fees are easy to understand and very very close to the multiplicative combination.
return fi + fj;
}
function _pairFeePpm(uint256 i, uint256 j) internal returns (uint256 fee) {
uint256 key = 1000 * i + j;
fee = _pairFees[key];
if (fee == 0) {
// store fee in cache
fee = _pairFeePpmView(i,j);
_pairFees[key] = fee;
}
}
// Convert uint token amount -> internal 64.64 (floor). Uses ABDKMath64x64.divu which truncates. // Convert uint token amount -> internal 64.64 (floor). Uses ABDKMath64x64.divu which truncates.
function _uintToInternalFloor(uint256 amount, uint256 base) internal pure returns (int128) { function _uintToInternalFloor(uint256 amount, uint256 base) internal pure returns (int128) {
// internal = amount / base (as Q64.64) // internal = amount / base (as Q64.64)

View File

@@ -1,40 +1,96 @@
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30; pragma solidity ^0.8.30;
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "./PartyPoolMintImpl.sol";
import {IPartyPool} from "./IPartyPool.sol"; import "./PartyPoolSwapImpl.sol";
import {IPartyPoolDeployer} from "./IPartyPoolDeployer.sol";
import {NativeWrapper} from "./NativeWrapper.sol";
import {PartyPool} from "./PartyPool.sol"; import {PartyPool} from "./PartyPool.sol";
import {PartyPoolBalancedPair} from "./PartyPoolBalancedPair.sol"; import {PartyPoolBalancedPair} from "./PartyPoolBalancedPair.sol";
import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
// This pattern is needed because the PartyPlanner constructs two different types of pools (regular and balanced-pair) // This pattern is needed because the PartyPlanner constructs two different types of pools (regular and balanced-pair)
// but doesn't have room to store the initialization code of both contracts. Therefore, we delegate pool construction. // but doesn't have room to store the initialization code of both contracts. Therefore, we delegate pool construction.
abstract contract BasePartyPoolDeployer is IPartyPoolDeployer { interface IPartyPoolDeployer {
uint256 private nonce; function deploy(
DeployParams public params; address owner_,
string memory name_,
function deploy(DeployParams memory params_) external returns (IPartyPool pool) { string memory symbol_,
params = params_; IERC20[] memory tokens_,
pool = _doDeploy(nonce); uint256[] memory bases_,
nonce += 1; int128 kappa_,
} uint256 swapFeePpm_,
uint256 flashFeePpm_,
function _doDeploy(uint256 nonce) virtual internal returns (IPartyPool pool); uint256 protocolFeePpm_,
address protocolFeeAddress_,
NativeWrapper wrapper_,
PartyPoolSwapImpl swapImpl_,
PartyPoolMintImpl mintImpl_
) external returns (IPartyPool pool);
} }
contract PartyPoolDeployer is IPartyPoolDeployer {
contract PartyPoolDeployer is BasePartyPoolDeployer { function deploy(
function _doDeploy(uint256 nonce) internal override returns (IPartyPool) { address owner_,
return new PartyPool(nonce); string memory name_,
string memory symbol_,
IERC20[] memory tokens_,
uint256[] memory bases_,
int128 kappa_,
uint256 swapFeePpm_,
uint256 flashFeePpm_,
uint256 protocolFeePpm_,
address protocolFeeAddress_,
NativeWrapper wrapper_,
PartyPoolSwapImpl swapImpl_,
PartyPoolMintImpl mintImpl_
) external returns (IPartyPool) {
return new PartyPool(
owner_,
name_,
symbol_,
tokens_,
bases_,
kappa_,
swapFeePpm_,
flashFeePpm_,
protocolFeePpm_,
protocolFeeAddress_,
wrapper_,
swapImpl_,
mintImpl_
);
} }
} }
contract PartyPoolBalancedPairDeployer is BasePartyPoolDeployer { contract PartyPoolBalancedPairDeployer is IPartyPoolDeployer {
function _doDeploy(uint256 nonce) internal override returns (IPartyPool) { function deploy(
return new PartyPoolBalancedPair(nonce); address owner_,
string memory name_,
string memory symbol_,
IERC20[] memory tokens_,
uint256[] memory bases_,
int128 kappa_,
uint256 swapFeePpm_,
uint256 flashFeePpm_,
uint256 protocolFeePpm_,
address protocolFeeAddress_,
NativeWrapper wrapper_,
PartyPoolSwapImpl swapImpl_,
PartyPoolMintImpl mintImpl_
) external returns (IPartyPool) {
return new PartyPoolBalancedPair(
owner_,
name_,
symbol_,
tokens_,
bases_,
kappa_,
swapFeePpm_,
flashFeePpm_,
protocolFeePpm_,
protocolFeeAddress_,
wrapper_,
swapImpl_,
mintImpl_
);
} }
} }

View File

@@ -25,46 +25,38 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Initialization Mint // Initialization Mint
// //
function initialMint(address receiver, uint256 lpTokens, int128 KAPPA) external payable native killable nonReentrant function initialMint(address receiver, uint256 lpTokens, int128 B_FIXED) external payable native killable nonReentrant
returns (uint256 lpMinted) { returns (uint256 lpMinted) {
uint256 n = _tokens.length; uint256 n = _tokens.length;
// Check if this is initial deposit - revert if not // Check if this is initial deposit - revert if not
bool isInitialDeposit = _totalSupply == 0 || _lmsr.qInternal.length == 0; bool isInitialDeposit = _totalSupply == 0 || _lmsr.nAssets == 0;
require(isInitialDeposit, "initialMint: pool already initialized"); require(isInitialDeposit, "initialMint: pool already initialized");
// Read initial on-chain balances, require all > 0, and compute denominators (bases) from deposits. // Update cached balances for all assets
// We assume equal-valued deposits; set base[i] = depositAmount so internal q_i starts at 1.0.
int128[] memory newQInternal = new int128[](n); int128[] memory newQInternal = new int128[](n);
uint256[] memory depositAmounts = new uint256[](n); uint256[] memory depositAmounts = new uint256[](n);
for (uint i = 0; i < n; ) { for (uint i = 0; i < n; ) {
uint256 bal = IERC20(_tokens[i]).balanceOf(address(this)); uint256 bal = IERC20(_tokens[i]).balanceOf(address(this));
require(bal > 0, "initialMint: zero initial balance");
depositAmounts[i] = bal;
// Cache external balances
_cachedUintBalances[i] = bal; _cachedUintBalances[i] = bal;
// Set per-asset denominator to the observed deposit amount (at least 1)
_bases[i] = bal;
// Compute internal q_i = bal / base_i => ~1.0 in 64.64
newQInternal[i] = _uintToInternalFloor(bal, _bases[i]); newQInternal[i] = _uintToInternalFloor(bal, _bases[i]);
require(newQInternal[i] > int128(0), "initialMint: zero internal q"); depositAmounts[i] = bal;
unchecked { i++; } unchecked { i++; }
} }
// Initialize the stabilized LMSR state with provided kappa // Initialize the stabilized LMSR state with provided fixed b
_lmsr.init(newQInternal, KAPPA); _lmsr.init(newQInternal, B_FIXED);
// Obey the passed-in initial LP amount. If 0, default to 1e18 // Compute actual LP _tokens to mint based on size metric (scaled)
lpMinted = lpTokens == 0 ? 1e18 : lpTokens; if( lpTokens != 0 )
lpMinted = lpTokens;
if (lpMinted > 0) { else {
_mint(receiver, lpMinted); int128 newTotal = _computeSizeMetric(newQInternal);
lpMinted = ABDKMath64x64.mulu(newTotal, LP_SCALE);
} }
require(lpMinted > 0, "initialMint: zero LP amount");
_mint(receiver, lpMinted);
emit IPartyPool.Mint(address(0), receiver, depositAmounts, lpMinted); emit IPartyPool.Mint(address(0), receiver, depositAmounts, lpMinted);
} }
@@ -79,7 +71,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 n = _tokens.length; uint256 n = _tokens.length;
// Check if this is NOT initial deposit - revert if it is // Check if this is NOT initial deposit - revert if it is
bool isInitialDeposit = _totalSupply == 0 || _lmsr.qInternal.length == 0; bool isInitialDeposit = _totalSupply == 0 || _lmsr.nAssets == 0;
require(!isInitialDeposit, "mint: use initialMint for pool initialization"); require(!isInitialDeposit, "mint: use initialMint for pool initialization");
require(lpTokenAmount > 0, "mint: zero LP amount"); require(lpTokenAmount > 0, "mint: zero LP amount");
@@ -88,7 +80,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE); uint256 oldScaled = ABDKMath64x64.mulu(oldTotal, LP_SCALE);
// Calculate required deposit amounts for the desired LP _tokens // Calculate required deposit amounts for the desired LP _tokens
uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, _totalSupply, _cachedUintBalances); uint256[] memory depositAmounts = mintAmounts(lpTokenAmount, _lmsr.nAssets, _totalSupply, _cachedUintBalances);
// Transfer in all token amounts // Transfer in all token amounts
for (uint i = 0; i < n; ) { for (uint i = 0; i < n; ) {
@@ -139,13 +131,13 @@ contract PartyPoolMintImpl is PartyPoolBase {
return actualLpToMint; return actualLpToMint;
} }
/// @notice Burn LP tokens and withdraw the proportional basket to receiver. Functional even if the pool /// @notice Burn LP _tokens and withdraw the proportional basket to receiver. Functional even if the pool has been
/// has been killed. /// killed.
/// @dev Payer must own or approve the LP tokens being burned. The function updates LMSR state /// @dev Payer must own or approve the LP _tokens being burned. The function updates LMSR state
/// proportionally to reflect the reduced pool size after the withdrawal. /// proportionally to reflect the reduced pool size after the withdrawal.
/// @param payer address that provides the LP tokens to burn /// @param payer address that provides the LP _tokens to burn
/// @param receiver address that receives the withdrawn tokens /// @param receiver address that receives the withdrawn _tokens
/// @param lpAmount amount of LP tokens to burn (proportional withdrawal) /// @param lpAmount amount of LP _tokens to burn (proportional withdrawal)
/// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore. /// @param deadline timestamp after which the transaction will revert. Pass 0 to ignore.
/// @param unwrap if true and the native token is being withdrawn, it is unwraped and sent as native currency /// @param unwrap if true and the native token is being withdrawn, it is unwraped and sent as native currency
function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline, bool unwrap) external nonReentrant function burn(address payer, address receiver, uint256 lpAmount, uint256 deadline, bool unwrap) external nonReentrant
@@ -160,7 +152,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Use cached balances; assume standard ERC20 transfers without external interference // Use cached balances; assume standard ERC20 transfers without external interference
// Compute proportional withdrawal amounts for the requested LP amount (rounded down) // Compute proportional withdrawal amounts for the requested LP amount (rounded down)
withdrawAmounts = burnAmounts(lpAmount, _totalSupply, _cachedUintBalances); withdrawAmounts = burnAmounts(lpAmount, _lmsr.nAssets, _totalSupply, _cachedUintBalances);
// Transfer underlying _tokens out to receiver according to computed proportions // Transfer underlying _tokens out to receiver according to computed proportions
for (uint i = 0; i < n; ) { for (uint i = 0; i < n; ) {
@@ -213,9 +205,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param lpTokenAmount The amount of LP _tokens desired /// @param lpTokenAmount The amount of LP _tokens desired
/// @return depositAmounts Array of token amounts to deposit (rounded up) /// @return depositAmounts Array of token amounts to deposit (rounded up)
function mintAmounts(uint256 lpTokenAmount, function mintAmounts(uint256 lpTokenAmount,
uint256 totalSupply, uint256[] memory cachedUintBalances) public pure uint256 numAssets, uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
returns (uint256[] memory depositAmounts) { returns (uint256[] memory depositAmounts) {
uint256 numAssets = cachedUintBalances.length;
depositAmounts = new uint256[](numAssets); depositAmounts = new uint256[](numAssets);
// If this is the first mint or pool is empty, return zeros // If this is the first mint or pool is empty, return zeros
@@ -237,9 +228,8 @@ contract PartyPoolMintImpl is PartyPoolBase {
} }
function burnAmounts(uint256 lpTokenAmount, function burnAmounts(uint256 lpTokenAmount,
uint256 totalSupply, uint256[] memory cachedUintBalances) public pure uint256 numAssets, uint256 totalSupply, uint256[] memory cachedUintBalances) public pure
returns (uint256[] memory withdrawAmounts) { returns (uint256[] memory withdrawAmounts) {
uint256 numAssets = cachedUintBalances.length;
withdrawAmounts = new uint256[](numAssets); withdrawAmounts = new uint256[](numAssets);
// If supply is zero or pool uninitialized, return zeros // If supply is zero or pool uninitialized, return zeros
@@ -269,9 +259,9 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param lmsrState current LMSR state /// @param lmsrState current LMSR state
/// @param bases_ scaling _bases for each token /// @param bases_ scaling _bases for each token
/// @param totalSupply_ current total LP token supply /// @param totalSupply_ current total LP token supply
/// @return amountIn actual input amount used (excluding fee) /// @return amountInUsed actual input amount used (excluding fee)
/// @return lpMinted LP tokens that would be minted /// @return fee fee amount charged
/// @return inFee fee amount charged /// @return lpMinted LP _tokens that would be minted
function swapMintAmounts( function swapMintAmounts(
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 maxAmountIn, uint256 maxAmountIn,
@@ -279,10 +269,10 @@ contract PartyPoolMintImpl is PartyPoolBase {
LMSRStabilized.State memory lmsrState, LMSRStabilized.State memory lmsrState,
uint256[] memory bases_, uint256[] memory bases_,
uint256 totalSupply_ uint256 totalSupply_
) public pure returns (uint256 amountIn, uint256 lpMinted, uint256 inFee) { ) public pure returns (uint256 amountInUsed, uint256 fee, uint256 lpMinted) {
require(inputTokenIndex < bases_.length, "swapMintAmounts: idx"); require(inputTokenIndex < bases_.length, "swapMintAmounts: idx");
require(maxAmountIn > 0, "swapMintAmounts: input zero"); require(maxAmountIn > 0, "swapMintAmounts: input zero");
require(lmsrState.qInternal.length > 0, "swapMintAmounts: uninit pool"); require(lmsrState.nAssets > 0, "swapMintAmounts: uninit pool");
// Compute fee on gross maxAmountIn to get an initial net estimate // Compute fee on gross maxAmountIn to get an initial net estimate
uint256 feeGuess = 0; uint256 feeGuess = 0;
@@ -298,20 +288,20 @@ contract PartyPoolMintImpl is PartyPoolBase {
// Use LMSR view to determine actual internal consumed and size-increase (ΔS) for mint // Use LMSR view to determine actual internal consumed and size-increase (ΔS) for mint
(int128 amountInInternalUsed, int128 sizeIncreaseInternal) = (int128 amountInInternalUsed, int128 sizeIncreaseInternal) =
LMSRStabilized.swapAmountsForMint(lmsrState.kappa, lmsrState.qInternal, LMSRStabilized.swapAmountsForMint(lmsrState.nAssets, lmsrState.bFixed, lmsrState.qInternal,
inputTokenIndex, netInternalGuess); inputTokenIndex, netInternalGuess);
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer // amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
uint256 amountInUsed = _internalToUintCeilPure(amountInInternalUsed, bases_[inputTokenIndex]); amountInUsed = _internalToUintCeilPure(amountInInternalUsed, bases_[inputTokenIndex]);
require(amountInUsed > 0, "swapMintAmounts: input zero after internal conversion"); require(amountInUsed > 0, "swapMintAmounts: input zero after internal conversion");
// Compute fee on the actual used input (ceiling) // Compute fee on the actual used input (ceiling)
inFee = 0; fee = 0;
if (swapFeePpm > 0) { if (swapFeePpm > 0) {
inFee = (amountInUsed * swapFeePpm + 999999) / 1000000; // ceil fee fee = (amountInUsed * swapFeePpm + 999999) / 1000000; // ceil fee
} }
amountIn = amountInUsed + inFee; uint256 totalTransfer = amountInUsed + fee;
require(amountIn > 0 && amountIn <= maxAmountIn, "swapMintAmounts: transfer exceeds max"); require(totalTransfer > 0 && totalTransfer <= maxAmountIn, "swapMintAmounts: transfer exceeds max");
// Compute old and new scaled size metrics to determine LP minted // Compute old and new scaled size metrics to determine LP minted
int128 oldTotal = _computeSizeMetricPure(lmsrState.qInternal); int128 oldTotal = _computeSizeMetricPure(lmsrState.qInternal);
@@ -347,7 +337,7 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @param maxAmountIn maximum uint token input (inclusive of fee) /// @param maxAmountIn maximum uint token input (inclusive of fee)
/// @param deadline optional deadline /// @param deadline optional deadline
/// @param swapFeePpm fee in parts-per-million for this pool /// @param swapFeePpm fee in parts-per-million for this pool
/// @return amountIn actual input used (uint256), lpMinted actual LP minted (uint256), inFee fee taken from the input (uint256) /// @return lpMinted actual LP minted (uint)
function swapMint( function swapMint(
address payer, address payer,
address receiver, address receiver,
@@ -356,12 +346,12 @@ contract PartyPoolMintImpl is PartyPoolBase {
uint256 deadline, uint256 deadline,
uint256 swapFeePpm, uint256 swapFeePpm,
uint256 protocolFeePpm uint256 protocolFeePpm
) external payable native killable nonReentrant returns (uint256 amountIn, uint256 lpMinted, uint256 inFee) { ) external payable native killable nonReentrant returns (uint256 lpMinted) {
uint256 n = _tokens.length; uint256 n = _tokens.length;
require(inputTokenIndex < n, "swapMint: idx"); require(inputTokenIndex < n, "swapMint: idx");
require(maxAmountIn > 0, "swapMint: input zero"); require(maxAmountIn > 0, "swapMint: input zero");
require(deadline == 0 || block.timestamp <= deadline, "swapMint: deadline"); require(deadline == 0 || block.timestamp <= deadline, "swapMint: deadline");
require(_lmsr.qInternal.length > 0, "swapMint: uninit pool"); require(_lmsr.nAssets > 0, "swapMint: uninit pool");
// compute fee on gross maxAmountIn to get an initial net estimate (we'll recompute based on actual used) // compute fee on gross maxAmountIn to get an initial net estimate (we'll recompute based on actual used)
(, uint256 netUintGuess) = _computeFee(maxAmountIn, swapFeePpm); (, uint256 netUintGuess) = _computeFee(maxAmountIn, swapFeePpm);
@@ -374,27 +364,27 @@ contract PartyPoolMintImpl is PartyPoolBase {
(int128 amountInInternalUsed, int128 sizeIncreaseInternal) = _lmsr.swapAmountsForMint(inputTokenIndex, netInternalGuess); (int128 amountInInternalUsed, int128 sizeIncreaseInternal) = _lmsr.swapAmountsForMint(inputTokenIndex, netInternalGuess);
// amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer // amountInInternalUsed may be <= netInternalGuess. Convert to uint (ceil) to determine actual transfer
uint256 amountInUsed = _internalToUintCeil(amountInInternalUsed, _bases[inputTokenIndex]); uint256 amountInUint = _internalToUintCeil(amountInInternalUsed, _bases[inputTokenIndex]);
require(amountInUsed > 0, "swapMint: input zero after internal conversion"); require(amountInUint > 0, "swapMint: input zero after internal conversion");
// Compute fee on the actual used input and total transfer amount (ceiling) // Compute fee on the actual used input and total transfer amount (ceiling)
inFee = _ceilFee(amountInUsed, swapFeePpm); uint256 feeUintActual = _ceilFee(amountInUint, swapFeePpm);
amountIn = amountInUsed + inFee; uint256 totalTransfer = amountInUint + feeUintActual;
require(amountIn > 0 && amountIn <= maxAmountIn, "swapMint: transfer exceeds max"); require(totalTransfer > 0 && totalTransfer <= maxAmountIn, "swapMint: transfer exceeds max");
// Transfer _tokens from payer (assume standard ERC20 without transfer fees) via helper // Transfer _tokens from payer (assume standard ERC20 without transfer fees) via helper
_receiveTokenFrom(payer, _tokens[inputTokenIndex], amountIn); _receiveTokenFrom(payer, _tokens[inputTokenIndex], totalTransfer);
// Accrue protocol share (floor) from the fee on the input token // Accrue protocol share (floor) from the fee on the input token
uint256 protoShare = 0; uint256 protoShare = 0;
if (protocolFeePpm > 0 && inFee > 0) { if (protocolFeePpm > 0 && feeUintActual > 0) {
protoShare = (inFee * protocolFeePpm) / 1_000_000; protoShare = (feeUintActual * protocolFeePpm) / 1_000_000;
if (protoShare > 0) { if (protoShare > 0) {
_protocolFeesOwed[inputTokenIndex] += protoShare; _protocolFeesOwed[inputTokenIndex] += protoShare;
} }
} }
// Update cached effective balance directly: add totalTransfer minus protocol share // Update cached effective balance directly: add totalTransfer minus protocol share
_cachedUintBalances[inputTokenIndex] += (amountIn - protoShare); _cachedUintBalances[inputTokenIndex] += (totalTransfer - protoShare);
// Compute old and new scaled size metrics to determine LP minted // Compute old and new scaled size metrics to determine LP minted
int128 oldTotal = _computeSizeMetric(_lmsr.qInternal); int128 oldTotal = _computeSizeMetric(_lmsr.qInternal);
@@ -403,22 +393,23 @@ contract PartyPoolMintImpl is PartyPoolBase {
int128 newTotal = oldTotal.add(sizeIncreaseInternal); int128 newTotal = oldTotal.add(sizeIncreaseInternal);
uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE); uint256 newScaled = ABDKMath64x64.mulu(newTotal, LP_SCALE);
uint256 actualLpToMint;
// Use natural ERC20 function since base contract inherits from ERC20 // Use natural ERC20 function since base contract inherits from ERC20
uint256 currentSupply = _totalSupply; uint256 currentSupply = _totalSupply;
if (currentSupply == 0) { if (currentSupply == 0) {
// If somehow supply zero (shouldn't happen as _lmsr.nAssets>0), mint newScaled // If somehow supply zero (shouldn't happen as _lmsr.nAssets>0), mint newScaled
lpMinted = newScaled; actualLpToMint = newScaled;
} else { } else {
uint256 delta = (newScaled > oldScaled) ? (newScaled - oldScaled) : 0; uint256 delta = (newScaled > oldScaled) ? (newScaled - oldScaled) : 0;
if (delta > 0) { if (delta > 0) {
// floor truncation rounds in favor of pool // floor truncation rounds in favor of pool
lpMinted = (currentSupply * delta) / oldScaled; actualLpToMint = (currentSupply * delta) / oldScaled;
} else { } else {
lpMinted = 0; actualLpToMint = 0;
} }
} }
require(lpMinted > 0, "swapMint: zero LP minted"); require(actualLpToMint > 0, "swapMint: zero LP minted");
// Update LMSR internal state: scale qInternal proportionally by newTotal/oldTotal // Update LMSR internal state: scale qInternal proportionally by newTotal/oldTotal
int128[] memory newQInternal = new int128[](n); int128[] memory newQInternal = new int128[](n);
@@ -431,18 +422,18 @@ contract PartyPoolMintImpl is PartyPoolBase {
_lmsr.updateForProportionalChange(newQInternal); _lmsr.updateForProportionalChange(newQInternal);
// Use natural ERC20 function since base contract inherits from ERC20 // Use natural ERC20 function since base contract inherits from ERC20
_mint(receiver, lpMinted); _mint(receiver, actualLpToMint);
emit IPartyPool.SwapMint(payer, receiver, _tokens[inputTokenIndex], emit IPartyPool.SwapMint(payer, receiver, _tokens[inputTokenIndex],
amountIn, lpMinted, inFee -protoShare, protoShare); totalTransfer, actualLpToMint, feeUintActual-protoShare, protoShare);
return (amountInUsed, lpMinted, inFee); return actualLpToMint;
} }
/// @notice Calculate the amounts for a burn swap operation /// @notice Calculate the amounts for a burn swap operation
/// @dev This is a pure view function that computes burn swap amounts from provided state /// @dev This is a pure view function that computes burn swap amounts from provided state
/// @param lpAmount amount of LP _tokens to burn /// @param lpAmount amount of LP _tokens to burn
/// @param outputTokenIndex index of target asset to receive /// @param inputTokenIndex index of target asset to receive
/// @param swapFeePpm fee in parts-per-million /// @param swapFeePpm fee in parts-per-million
/// @param lmsrState current LMSR state /// @param lmsrState current LMSR state
/// @param bases_ scaling _bases for each token /// @param bases_ scaling _bases for each token
@@ -450,54 +441,52 @@ contract PartyPoolMintImpl is PartyPoolBase {
/// @return amountOut amount of target asset that would be received /// @return amountOut amount of target asset that would be received
function burnSwapAmounts( function burnSwapAmounts(
uint256 lpAmount, uint256 lpAmount,
uint256 outputTokenIndex, uint256 inputTokenIndex,
uint256 swapFeePpm, uint256 swapFeePpm,
LMSRStabilized.State memory lmsrState, LMSRStabilized.State memory lmsrState,
uint256[] memory bases_, uint256[] memory bases_,
uint256 totalSupply_ uint256 totalSupply_
) public pure returns (uint256 amountOut, uint256 outFee) { ) public pure returns (uint256 amountOut) {
require(outputTokenIndex < bases_.length, "burnSwapAmounts: idx"); require(inputTokenIndex < bases_.length, "burnSwapAmounts: idx");
require(lpAmount > 0, "burnSwapAmounts: zero lp"); require(lpAmount > 0, "burnSwapAmounts: zero lp");
require(totalSupply_ > 0, "burnSwapAmounts: empty supply"); require(totalSupply_ > 0, "burnSwapAmounts: empty supply");
// alpha = lpAmount / supply as Q64.64 // alpha = lpAmount / supply as Q64.64
int128 alpha = ABDKMath64x64.divu(lpAmount, totalSupply_); int128 alpha = ABDKMath64x64.divu(lpAmount, totalSupply_) // fraction of total supply to burn
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
// Use LMSR view to compute single-asset payout and burned size-metric // Use LMSR view to compute single-asset payout and burned size-metric
(, int128 payoutInternal) = LMSRStabilized.swapAmountsForBurn(lmsrState.kappa, lmsrState.qInternal, (int128 payoutInternal, ) = LMSRStabilized.swapAmountsForBurn(lmsrState.nAssets, lmsrState.bFixed, lmsrState.qInternal,
outputTokenIndex, alpha); inputTokenIndex, alpha);
// Convert payoutInternal -> uint (floor) to favor pool // Convert payoutInternal -> uint (floor) to favor pool
uint256 grossAmountOut = _internalToUintFloorPure(payoutInternal, bases_[outputTokenIndex]); amountOut = _internalToUintFloorPure(payoutInternal, bases_[inputTokenIndex]);
(outFee,) = _computeFee(grossAmountOut, swapFeePpm); require(amountOut > 0, "burnSwapAmounts: output zero");
require(grossAmountOut > outFee, "burnSwapAmounts: output zero");
amountOut = grossAmountOut - outFee;
} }
/// @notice Burn LP _tokens then swap the redeemed proportional basket into a single asset `outputTokenIndex` and send to receiver. /// @notice Burn LP _tokens then swap the redeemed proportional basket into a single asset `inputTokenIndex` and send to receiver.
/// This version of burn does not work if the vault has been killed, because it involves a swap. Use regular burn() /// This version of burn does not work if the vault has been killed, because it involves a swap. Use regular burn()
/// to recover funds if the pool has been killed. /// to recover funds if the pool has been killed.
/// @dev The function burns LP _tokens (authorization via allowance if needed), sends the single-asset payout and updates LMSR state. /// @dev The function burns LP _tokens (authorization via allowance if needed), sends the single-asset payout and updates LMSR state.
/// @param payer who burns LP _tokens /// @param payer who burns LP _tokens
/// @param receiver who receives the single asset /// @param receiver who receives the single asset
/// @param lpAmount amount of LP _tokens to burn /// @param lpAmount amount of LP _tokens to burn
/// @param outputTokenIndex index of target asset to receive /// @param inputTokenIndex index of target asset to receive
/// @param deadline optional deadline /// @param deadline optional deadline
/// @param swapFeePpm fee in parts-per-million for this pool (may be used for future fee logic) /// @param swapFeePpm fee in parts-per-million for this pool (may be used for future fee logic)
/// @return amountOut uint amount of asset i sent to receiver /// @return amountOutUint uint amount of asset i sent to receiver
/// @return outFee uint amount of asset i kept as an LP and protocol fee
function burnSwap( function burnSwap(
address payer, address payer,
address receiver, address receiver,
uint256 lpAmount, uint256 lpAmount,
uint256 outputTokenIndex, uint256 inputTokenIndex,
uint256 deadline, uint256 deadline,
bool unwrap, bool unwrap,
uint256 swapFeePpm, uint256 swapFeePpm,
uint256 protocolFeePpm uint256 protocolFeePpm
) external nonReentrant killable returns (uint256 amountOut, uint256 outFee) { ) external nonReentrant killable returns (uint256 amountOutUint) {
uint256 n = _tokens.length; uint256 n = _tokens.length;
require(outputTokenIndex < n, "burnSwap: idx"); require(inputTokenIndex < n, "burnSwap: idx");
require(lpAmount > 0, "burnSwap: zero lp"); require(lpAmount > 0, "burnSwap: zero lp");
require(deadline == 0 || block.timestamp <= deadline, "burnSwap: deadline"); require(deadline == 0 || block.timestamp <= deadline, "burnSwap: deadline");
@@ -505,26 +494,35 @@ contract PartyPoolMintImpl is PartyPoolBase {
require(supply > 0, "burnSwap: empty supply"); require(supply > 0, "burnSwap: empty supply");
// alpha = lpAmount / supply as Q64.64 (adjusted for fee) // alpha = lpAmount / supply as Q64.64 (adjusted for fee)
int128 alpha = ABDKMath64x64.divu(lpAmount, supply); // fraction of total supply to burn int128 alpha = ABDKMath64x64.divu(lpAmount, supply) // fraction of total supply to burn
.mul(ABDKMath64x64.divu(1000000-swapFeePpm, 1000000)); // adjusted for fee
// Use LMSR view to compute single-asset payout and burned size-metric // Use LMSR view to compute single-asset payout and burned size-metric
(, int128 payoutInternal) = _lmsr.swapAmountsForBurn(outputTokenIndex, alpha); (int128 payoutInternal, ) = _lmsr.swapAmountsForBurn(inputTokenIndex, alpha);
// Convert payoutInternal -> uint (floor) to favor pool // Convert payoutInternal -> uint (floor) to favor pool
uint256 payoutGrossUint = _internalToUintFloorPure(payoutInternal, _bases[outputTokenIndex]); amountOutUint = _internalToUintFloor(payoutInternal, _bases[inputTokenIndex]);
(outFee,) = _computeFee(payoutGrossUint, swapFeePpm); require(amountOutUint > 0, "burnSwap: output zero");
require(payoutGrossUint > outFee, "burnSwapAmounts: output zero");
amountOut = payoutGrossUint - outFee; // Compute gross payout (no swap fee) so we can determine token-side fee = gross - net
int128 alphaGross = ABDKMath64x64.divu(lpAmount, supply); // gross fraction (no swap fee)
(int128 payoutGrossInternal, ) = _lmsr.swapAmountsForBurn(inputTokenIndex, alphaGross);
uint256 payoutGrossUint = _internalToUintFloor(payoutGrossInternal, _bases[inputTokenIndex]);
uint256 feeTokenUint = (payoutGrossUint > amountOutUint) ? (payoutGrossUint - amountOutUint) : 0;
// Accrue protocol share (floor) from the token-side fee // Accrue protocol share (floor) from the token-side fee
uint256 protoShare = 0; uint256 protoShare = 0;
if (protocolFeePpm > 0 && outFee > 0) { if (protocolFeePpm > 0 && feeTokenUint > 0) {
protoShare = (outFee * protocolFeePpm) / 1_000_000; protoShare = (feeTokenUint * protocolFeePpm) / 1_000_000;
if (protoShare > 0) { if (protoShare > 0) {
_protocolFeesOwed[outputTokenIndex] += protoShare; _protocolFeesOwed[inputTokenIndex] += protoShare;
} }
} }
// Transfer the payout to receiver via centralized helper
IERC20 inputToken = _tokens[inputTokenIndex];
_sendTokenTo(inputToken, receiver, amountOutUint, unwrap);
// Burn LP _tokens from payer (authorization via allowance) // Burn LP _tokens from payer (authorization via allowance)
if (msg.sender != payer) { if (msg.sender != payer) {
uint256 allowed = _allowances[payer][msg.sender]; uint256 allowed = _allowances[payer][msg.sender];
@@ -532,19 +530,13 @@ contract PartyPoolMintImpl is PartyPoolBase {
} }
_burn(payer, lpAmount); _burn(payer, lpAmount);
// Transfer the payout to receiver via centralized helper
IERC20 outputToken = _tokens[outputTokenIndex];
_sendTokenTo(outputToken, receiver, amountOut, unwrap);
// Update cached balances using computed payout and protocol fee; no on-chain reads // Update cached balances using computed payout and protocol fee; no on-chain reads
int128[] memory newQInternal = new int128[](n); int128[] memory newQInternal = new int128[](n);
for (uint256 idx = 0; idx < n; idx++) { for (uint256 idx = 0; idx < n; idx++) {
uint256 newBal = _cachedUintBalances[idx]; uint256 newBal = _cachedUintBalances[idx];
if (idx == outputTokenIndex) { if (idx == inputTokenIndex) {
// Effective LP balance decreases by net payout and increased protocol owed // Effective LP balance decreases by net payout and increased protocol owed
newBal = newBal - amountOut - protoShare; newBal = newBal - amountOutUint - protoShare;
} }
_cachedUintBalances[idx] = newBal; _cachedUintBalances[idx] = newBal;
newQInternal[idx] = _uintToInternalFloor(newBal, _bases[idx]); newQInternal[idx] = _uintToInternalFloor(newBal, _bases[idx]);
@@ -561,8 +553,10 @@ contract PartyPoolMintImpl is PartyPoolBase {
_lmsr.updateForProportionalChange(newQInternal); _lmsr.updateForProportionalChange(newQInternal);
} }
emit IPartyPool.BurnSwap(payer, receiver, outputToken, lpAmount, amountOut, emit IPartyPool.BurnSwap(payer, receiver, inputToken, lpAmount, amountOutUint,
outFee-protoShare, protoShare); feeTokenUint-protoShare, protoShare);
return amountOutUint;
} }
/// @notice Pure version of _uintToInternalFloor for use in view functions /// @notice Pure version of _uintToInternalFloor for use in view functions

View File

@@ -8,7 +8,6 @@ import {IPartyPool} from "./IPartyPool.sol";
import {NativeWrapper} from "./NativeWrapper.sol"; import {NativeWrapper} from "./NativeWrapper.sol";
import {LMSRStabilized} from "./LMSRStabilized.sol"; import {LMSRStabilized} from "./LMSRStabilized.sol";
import {PartyPoolBase} from "./PartyPoolBase.sol"; import {PartyPoolBase} from "./PartyPoolBase.sol";
import {IERC3156FlashBorrower} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
/// @title PartyPoolSwapMintImpl - Implementation contract for swapMint and burnSwap functions /// @title PartyPoolSwapMintImpl - Implementation contract for swapMint and burnSwap functions
/// @notice This contract contains the swapMint and burnSwap implementation that will be called via delegatecall /// @notice This contract contains the swapMint and burnSwap implementation that will be called via delegatecall
@@ -20,71 +19,29 @@ contract PartyPoolSwapImpl is PartyPoolBase {
constructor(NativeWrapper wrapper_) PartyPoolBase(wrapper_) {} constructor(NativeWrapper wrapper_) PartyPoolBase(wrapper_) {}
bytes32 internal constant FLASH_CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan");
function flashLoan(
IERC3156FlashBorrower receiver,
address tokenAddr,
uint256 amount,
bytes calldata data,
uint256 flashFeePpm,
uint256 protocolFeePpm
) external nonReentrant killable returns (bool) {
IERC20 token = IERC20(tokenAddr);
require(amount <= token.balanceOf(address(this)), "flash: amount > balance");
uint256 tokenIndex = _tokenAddressToIndexPlusOne[token];
require(tokenIndex != 0, 'flash: token not in pool');
tokenIndex -= 1;
(uint256 flashFee, ) = _computeFee(amount, flashFeePpm);
// Compute protocol share of flash fee
uint256 protoShare = 0;
if (protocolFeePpm > 0 && flashFee > 0) {
protoShare = (flashFee * protocolFeePpm) / 1_000_000; // floor
if (protoShare > 0) {
_protocolFeesOwed[tokenIndex] += protoShare;
}
}
_sendTokenTo(token, address(receiver), amount, false);
require(
receiver.onFlashLoan(msg.sender, address(token), amount, flashFee, data) == FLASH_CALLBACK_SUCCESS,
'flash: callback'
);
_receiveTokenFrom(address(receiver), token, amount + flashFee);
// Update cached balance for the borrowed token
uint256 balAfter = token.balanceOf(address(this));
require(balAfter >= _protocolFeesOwed[tokenIndex], "balance < protocol owed");
_cachedUintBalances[tokenIndex] = balAfter - _protocolFeesOwed[tokenIndex];
emit IPartyPool.Flash(msg.sender, receiver, token, amount, flashFee - protoShare, protoShare);
return true;
}
function swapToLimitAmounts( function swapToLimitAmounts(
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
int128 limitPrice, int128 limitPrice,
uint256[] memory bases, uint256[] memory bases,
int128 kappa, int128 b,
int128[] memory qInternal, int128[] memory qInternal,
uint256 swapFeePpm uint256 swapFeePpm
) external pure returns (uint256 amountIn, uint256 amountOut, uint256 inFee) { ) external pure returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
// Compute internal maxima at the price limit // Compute internal maxima at the price limit
(int128 amountInInternal, int128 amountOutInternal) = LMSRStabilized.swapAmountsForPriceLimit( (int128 amountInInternal, int128 amountOutInternal) = LMSRStabilized.swapAmountsForPriceLimit(
kappa, qInternal, bases.length, b, qInternal,
inputTokenIndex, outputTokenIndex, limitPrice); inputTokenIndex, outputTokenIndex, limitPrice);
// Convert input to uint (ceil) and output to uint (floor) // Convert input to uint (ceil) and output to uint (floor)
uint256 amountInUintNoFee = _internalToUintCeil(amountInInternal, bases[inputTokenIndex]); uint256 amountInUintNoFee = _internalToUintCeil(amountInInternal, bases[inputTokenIndex]);
require(amountInUintNoFee > 0, "swapToLimit: input zero"); require(amountInUintNoFee > 0, "swapToLimit: input zero");
inFee = 0; fee = 0;
amountIn = amountInUintNoFee; amountIn = amountInUintNoFee;
if (swapFeePpm > 0) { if (swapFeePpm > 0) {
inFee = _ceilFee(amountInUintNoFee, swapFeePpm); fee = _ceilFee(amountInUintNoFee, swapFeePpm);
amountIn += inFee; amountIn += fee;
} }
amountOut = _internalToUintFloor(amountOutInternal, bases[outputTokenIndex]); amountOut = _internalToUintFloor(amountOutInternal, bases[outputTokenIndex]);
@@ -102,7 +59,7 @@ contract PartyPoolSwapImpl is PartyPoolBase {
bool unwrap, bool unwrap,
uint256 swapFeePpm, uint256 swapFeePpm,
uint256 protocolFeePpm uint256 protocolFeePpm
) external payable native killable nonReentrant returns (uint256 amountInUsed, uint256 amountOut, uint256 inFee) { ) external payable native killable nonReentrant returns (uint256 amountInUsed, uint256 amountOut, uint256 fee) {
uint256 n = _tokens.length; uint256 n = _tokens.length;
require(inputTokenIndex < n && outputTokenIndex < n, "swapToLimit: idx"); require(inputTokenIndex < n && outputTokenIndex < n, "swapToLimit: idx");
require(limitPrice > int128(0), "swapToLimit: limit <= 0"); require(limitPrice > int128(0), "swapToLimit: limit <= 0");

View File

@@ -1,17 +1,16 @@
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30; pragma solidity ^0.8.30;
import "forge-std/console2.sol";
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol"; import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {IPartyPool} from "./IPartyPool.sol"; import {IPartyPool} from "./IPartyPool.sol";
import {IPartyInfo} from "./IPartyInfo.sol";
import {LMSRStabilized} from "./LMSRStabilized.sol"; import {LMSRStabilized} from "./LMSRStabilized.sol";
import {PartyPoolHelpers} from "./PartyPoolHelpers.sol"; import {PartyPoolHelpers} from "./PartyPoolHelpers.sol";
import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol"; import {PartyPoolMintImpl} from "./PartyPoolMintImpl.sol";
import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol"; import {PartyPoolSwapImpl} from "./PartyPoolSwapImpl.sol";
import {IPartyPoolViewer} from "./IPartyPoolViewer.sol";
contract PartyInfo is PartyPoolHelpers, IPartyInfo { contract PartyPoolViewer is PartyPoolHelpers, IPartyPoolViewer {
using ABDKMath64x64 for int128; using ABDKMath64x64 for int128;
PartyPoolSwapImpl immutable internal SWAP_IMPL; PartyPoolSwapImpl immutable internal SWAP_IMPL;
@@ -22,16 +21,6 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
MINT_IMPL = mintImpl; MINT_IMPL = mintImpl;
} }
function working(IPartyPool pool) external view returns (bool) {
if (pool.killed())
return false;
LMSRStabilized.State memory s = pool.LMSR();
for( uint i=0; i<s.qInternal.length; i++ )
if (s.qInternal[i] > 0)
return true;
return false;
}
// //
// Current marginal prices // Current marginal prices
// //
@@ -44,14 +33,9 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
/// @return price Q64.64 value equal to quote per base (p_quote / p_base) /// @return price Q64.64 value equal to quote per base (p_quote / p_base)
function price(IPartyPool pool, uint256 baseTokenIndex, uint256 quoteTokenIndex) external view returns (int128) { function price(IPartyPool pool, uint256 baseTokenIndex, uint256 quoteTokenIndex) external view returns (int128) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length; require(baseTokenIndex < lmsr.nAssets && quoteTokenIndex < lmsr.nAssets, "price: idx");
require(nAssets > 0, "price: uninit"); require(lmsr.nAssets > 0, "price: uninit");
require(baseTokenIndex < nAssets && quoteTokenIndex < nAssets, "price: idx"); return LMSRStabilized.price(lmsr.nAssets, pool.bFixed(), lmsr.qInternal, baseTokenIndex, quoteTokenIndex);
int128 internalPrice = LMSRStabilized.price(pool.kappa(), lmsr.qInternal, baseTokenIndex, quoteTokenIndex);
// Convert to external units
uint256 bd = pool.denominators()[baseTokenIndex];
uint256 qd = pool.denominators()[quoteTokenIndex];
return internalPrice.mul(ABDKMath64x64.divu(bd, qd));
} }
/// @notice Price of one LP token denominated in `quote` as Q64.64. /// @notice Price of one LP token denominated in `quote` as Q64.64.
@@ -62,32 +46,44 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
/// @return price Q64.64 value equal to quote per LP token unit /// @return price Q64.64 value equal to quote per LP token unit
function poolPrice(IPartyPool pool, uint256 quoteTokenIndex) external view returns (int128) { function poolPrice(IPartyPool pool, uint256 quoteTokenIndex) external view returns (int128) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length; require(lmsr.nAssets > 0, "poolPrice: uninit");
require(nAssets > 0, "poolPrice: uninit"); require(quoteTokenIndex < lmsr.nAssets, "poolPrice: idx");
require(quoteTokenIndex < nAssets, "poolPrice: idx");
// price per unit of qTotal (Q64.64) from LMSR // price per unit of qTotal (Q64.64) from LMSR
return LMSRStabilized.poolPrice( pool.kappa(), lmsr.qInternal, quoteTokenIndex); int128 pricePerQ = LMSRStabilized.poolPrice(lmsr.nAssets, pool.bFixed(), lmsr.qInternal, quoteTokenIndex);
// total internal q (qTotal) as Q64.64
int128 qTotal = LMSRStabilized._computeSizeMetric(lmsr.qInternal);
require(qTotal > int128(0), "poolPrice: qTotal zero");
// totalSupply as Q64.64
uint256 supply = pool.totalSupply();
require(supply > 0, "poolPrice: zero supply");
int128 supplyQ64 = ABDKMath64x64.fromUInt(supply);
// factor = totalSupply / qTotal (Q64.64)
int128 factor = supplyQ64.div(qTotal);
// price per LP token = pricePerQ * factor (Q64.64)
return pricePerQ.mul(factor);
} }
function mintAmounts(IPartyPool pool, uint256 lpTokenAmount) public view returns (uint256[] memory depositAmounts) { function mintAmounts(IPartyPool pool, uint256 lpTokenAmount) public view returns (uint256[] memory depositAmounts) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length; uint256[] memory cachedUintBalances = new uint256[](lmsr.nAssets);
uint256[] memory cachedUintBalances = new uint256[](nAssets); for( uint256 i=0; i<lmsr.nAssets; i++ )
for( uint256 i=0; i<nAssets; i++ )
cachedUintBalances[i] = pool.getToken(i).balanceOf(address(pool)); cachedUintBalances[i] = pool.getToken(i).balanceOf(address(pool));
return MINT_IMPL.mintAmounts(lpTokenAmount, pool.totalSupply(), cachedUintBalances); return MINT_IMPL.mintAmounts(lpTokenAmount, lmsr.nAssets, pool.totalSupply(), cachedUintBalances);
} }
function burnAmounts(IPartyPool pool, uint256 lpTokenAmount) external view returns (uint256[] memory withdrawAmounts) { function burnAmounts(IPartyPool pool, uint256 lpTokenAmount) external view returns (uint256[] memory withdrawAmounts) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length; uint256[] memory cachedUintBalances = new uint256[](lmsr.nAssets);
uint256[] memory cachedUintBalances = new uint256[](nAssets); for( uint256 i=0; i<lmsr.nAssets; i++ )
for( uint256 i=0; i<nAssets; i++ )
cachedUintBalances[i] = pool.getToken(i).balanceOf(address(pool)); cachedUintBalances[i] = pool.getToken(i).balanceOf(address(pool));
return MINT_IMPL.burnAmounts(lpTokenAmount, pool.totalSupply(), cachedUintBalances); return MINT_IMPL.burnAmounts(lpTokenAmount, lmsr.nAssets, pool.totalSupply(), cachedUintBalances);
} }
@@ -95,32 +91,31 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
/// @param inputTokenIndex index of input token /// @param inputTokenIndex index of input token
/// @param outputTokenIndex index of output token /// @param outputTokenIndex index of output token
/// @param limitPrice target marginal price to reach (must be > 0) /// @param limitPrice target marginal price to reach (must be > 0)
/// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, inFee fee amount taken /// @return amountIn gross input amount to transfer (includes fee), amountOut output amount user would receive, fee fee amount taken
function swapToLimitAmounts( function swapToLimitAmounts(
IPartyPool pool, IPartyPool pool,
uint256 inputTokenIndex, uint256 inputTokenIndex,
uint256 outputTokenIndex, uint256 outputTokenIndex,
int128 limitPrice int128 limitPrice
) external view returns (uint256 amountIn, uint256 amountOut, uint256 inFee) { ) external view returns (uint256 amountIn, uint256 amountOut, uint256 fee) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
uint256 nAssets = lmsr.qInternal.length; require(inputTokenIndex < lmsr.nAssets && outputTokenIndex < lmsr.nAssets, "swapToLimit: idx");
require(inputTokenIndex < nAssets && outputTokenIndex < nAssets, "swapToLimit: idx");
require(limitPrice > int128(0), "swapToLimit: limit <= 0"); require(limitPrice > int128(0), "swapToLimit: limit <= 0");
require(nAssets > 0, "swapToLimit: pool uninitialized"); require(lmsr.nAssets > 0, "swapToLimit: pool uninitialized");
return SWAP_IMPL.swapToLimitAmounts( return SWAP_IMPL.swapToLimitAmounts(
inputTokenIndex, outputTokenIndex, limitPrice, inputTokenIndex, outputTokenIndex, limitPrice,
pool.denominators(), pool.kappa(), lmsr.qInternal, pool.fee(inputTokenIndex, outputTokenIndex)); pool.denominators(), pool.bFixed(), lmsr.qInternal, pool.swapFeePpm());
} }
function swapMintAmounts(IPartyPool pool, uint256 inputTokenIndex, uint256 maxAmountIn) external view function swapMintAmounts(IPartyPool pool, uint256 inputTokenIndex, uint256 maxAmountIn) external view
returns (uint256 amountInUsed, uint256 lpMinted, uint256 inFee) { returns (uint256 amountInUsed, uint256 fee, uint256 lpMinted) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
return MINT_IMPL.swapMintAmounts( return MINT_IMPL.swapMintAmounts(
inputTokenIndex, inputTokenIndex,
maxAmountIn, maxAmountIn,
pool.fees()[inputTokenIndex], pool.swapFeePpm(),
lmsr, lmsr,
pool.denominators(), pool.denominators(),
pool.totalSupply() pool.totalSupply()
@@ -128,13 +123,13 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
} }
function burnSwapAmounts(IPartyPool pool, uint256 lpAmount, uint256 outputTokenIndex) external view function burnSwapAmounts(IPartyPool pool, uint256 lpAmount, uint256 inputTokenIndex) external view
returns (uint256 amountOut, uint256 outFee) { returns (uint256 amountOut) {
LMSRStabilized.State memory lmsr = pool.LMSR(); LMSRStabilized.State memory lmsr = pool.LMSR();
return MINT_IMPL.burnSwapAmounts( return MINT_IMPL.burnSwapAmounts(
lpAmount, lpAmount,
outputTokenIndex, inputTokenIndex,
pool.fees()[outputTokenIndex], pool.swapFeePpm(),
lmsr, lmsr,
pool.denominators(), pool.denominators(),
pool.totalSupply() pool.totalSupply()
@@ -142,6 +137,22 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
} }
/// @notice Compute repayment amounts (principal + flash fee) for a proposed flash loan.
/// @param loanAmounts array of per-token loan amounts; must match the pool's token ordering.
/// @return repaymentAmounts array where repaymentAmounts[i] = loanAmounts[i] + ceil(loanAmounts[i] * flashFeePpm)
function flashRepaymentAmounts(IPartyPool pool, uint256[] memory loanAmounts) external view
returns (uint256[] memory repaymentAmounts) {
LMSRStabilized.State memory lmsr = pool.LMSR();
repaymentAmounts = new uint256[](lmsr.nAssets);
for (uint256 i = 0; i < lmsr.nAssets; i++) {
uint256 amount = loanAmounts[i];
if (amount > 0) {
repaymentAmounts[i] = amount + _ceilFee(amount, pool.flashFeePpm());
}
}
}
/** /**
* @dev The amount of currency available to be lent. * @dev The amount of currency available to be lent.
* @param token The loan currency. * @param token The loan currency.
@@ -154,9 +165,11 @@ contract PartyInfo is PartyPoolHelpers, IPartyInfo {
return IERC20(token).balanceOf(address(pool)); return IERC20(token).balanceOf(address(pool));
} }
/// @dev The fee to be charged for a given loan. /**
/// @param amount The amount of _tokens lent. * @dev The fee to be charged for a given loan.
/// @return fee The amount of `token` to be charged for the loan, on top of the returned principal. * @param amount The amount of _tokens lent.
* @return fee The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee( function flashFee(
IPartyPool pool, IPartyPool pool,
address /*token*/, address /*token*/,

View File

@@ -9,7 +9,7 @@ import {PartyPoolBalancedPair} from "../src/PartyPoolBalancedPair.sol";
import {PartyPoolDeployer, PartyPoolBalancedPairDeployer} from "../src/PartyPoolDeployer.sol"; import {PartyPoolDeployer, PartyPoolBalancedPairDeployer} from "../src/PartyPoolDeployer.sol";
import {PartyPoolMintImpl} from "../src/PartyPoolMintImpl.sol"; import {PartyPoolMintImpl} from "../src/PartyPoolMintImpl.sol";
import {PartyPoolSwapImpl} from "../src/PartyPoolSwapImpl.sol"; import {PartyPoolSwapImpl} from "../src/PartyPoolSwapImpl.sol";
import {PartyInfo} from "../src/PartyInfo.sol"; import {PartyPoolViewer} from "../src/PartyPoolViewer.sol";
import {WETH9} from "./WETH9.sol"; import {WETH9} from "./WETH9.sol";
library Deploy { library Deploy {
@@ -44,13 +44,14 @@ library Deploy {
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
IERC20[] memory tokens_, IERC20[] memory tokens_,
uint256[] memory bases_,
int128 _kappa, int128 _kappa,
uint256 _swapFeePpm, uint256 _swapFeePpm,
uint256 _flashFeePpm, uint256 _flashFeePpm,
bool _stable bool _stable
) internal returns (PartyPool) { ) internal returns (PartyPool) {
NativeWrapper wrapper = new WETH9(); NativeWrapper wrapper = new WETH9();
return newPartyPool(owner_, name_, symbol_, tokens_, _kappa, _swapFeePpm, _flashFeePpm, wrapper, _stable); return newPartyPool(owner_, name_, symbol_, tokens_, bases_, _kappa, _swapFeePpm, _flashFeePpm, wrapper, _stable);
} }
function newPartyPool( function newPartyPool(
@@ -58,23 +59,22 @@ library Deploy {
string memory name_, string memory name_,
string memory symbol_, string memory symbol_,
IERC20[] memory tokens_, IERC20[] memory tokens_,
uint256[] memory bases_,
int128 _kappa, int128 _kappa,
uint256 _swapFeePpm, uint256 _swapFeePpm,
uint256 _flashFeePpm, uint256 _flashFeePpm,
NativeWrapper wrapper, NativeWrapper wrapper,
bool _stable bool _stable
) internal returns (PartyPool) { ) internal returns (PartyPool) {
// Build per-asset fee vector from scalar for tests
uint256[] memory feesArr = new uint256[](tokens_.length);
for (uint256 i = 0; i < tokens_.length; i++) { feesArr[i] = _swapFeePpm; }
return _stable && tokens_.length == 2 ? return _stable && tokens_.length == 2 ?
new PartyPoolBalancedPair( new PartyPoolBalancedPair(
owner_, owner_,
name_, name_,
symbol_, symbol_,
tokens_, tokens_,
bases_,
_kappa, _kappa,
feesArr, _swapFeePpm,
_flashFeePpm, _flashFeePpm,
PROTOCOL_FEE_PPM, PROTOCOL_FEE_PPM,
PROTOCOL_FEE_RECEIVER, PROTOCOL_FEE_RECEIVER,
@@ -87,8 +87,9 @@ library Deploy {
name_, name_,
symbol_, symbol_,
tokens_, tokens_,
bases_,
_kappa, _kappa,
feesArr, _swapFeePpm,
_flashFeePpm, _flashFeePpm,
PROTOCOL_FEE_PPM, PROTOCOL_FEE_PPM,
PROTOCOL_FEE_RECEIVER, PROTOCOL_FEE_RECEIVER,
@@ -99,8 +100,8 @@ library Deploy {
} }
function newInfo() internal returns (PartyInfo) { function newViewer() internal returns (PartyPoolViewer) {
NativeWrapper wrapper = new WETH9(); NativeWrapper wrapper = new WETH9();
return new PartyInfo(new PartyPoolSwapImpl(wrapper), new PartyPoolMintImpl(wrapper)); return new PartyPoolViewer(new PartyPoolSwapImpl(wrapper), new PartyPoolMintImpl(wrapper));
} }
} }

View File

@@ -1,26 +1,16 @@
// SPDX-License-Identifier: UNLICENSED // SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30; pragma solidity ^0.8.30;
import {ABDKMath64x64} from "../lib/abdk-libraries-solidity/ABDKMath64x64.sol";
import {CommonBase} from "../lib/forge-std/src/Base.sol";
import {StdAssertions} from "../lib/forge-std/src/StdAssertions.sol";
import {StdChains} from "../lib/forge-std/src/StdChains.sol";
import {StdCheats, StdCheatsSafe} from "../lib/forge-std/src/StdCheats.sol";
import {StdUtils} from "../lib/forge-std/src/StdUtils.sol";
import {Test} from "../lib/forge-std/src/Test.sol";
import {IERC3156FlashBorrower} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
import {ERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {IPartyPool} from "../src/IPartyPool.sol";
import {LMSRStabilized} from "../src/LMSRStabilized.sol";
import {PartyPlanner} from "../src/PartyPlanner.sol";
import {PartyPool} from "../src/PartyPool.sol";
import {Deploy} from "./Deploy.sol";
import {TestERC20, FlashBorrower} from "./GasTest.sol";
/* solhint-disable erc20-unchecked-transfer */ /* solhint-disable erc20-unchecked-transfer */
import "forge-std/Test.sol";
import "@abdk/ABDKMath64x64.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../src/LMSRStabilized.sol";
import "../src/PartyPool.sol";
import "../src/PartyPlanner.sol";
import "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
import {Deploy} from "./Deploy.sol";
/// @notice Test contract that implements the flash callback for testing flash loans /// @notice Test contract that implements the flash callback for testing flash loans
contract FlashBorrower is IERC3156FlashBorrower { contract FlashBorrower is IERC3156FlashBorrower {
enum Action { enum Action {
@@ -109,10 +99,10 @@ contract GasTest is Test {
using SafeERC20 for TestERC20; using SafeERC20 for TestERC20;
PartyPlanner internal planner; PartyPlanner internal planner;
IPartyPool internal pool2; PartyPool internal pool2;
IPartyPool internal pool10; PartyPool internal pool10;
IPartyPool internal pool20; PartyPool internal pool20;
IPartyPool internal pool50; PartyPool internal pool50;
address internal alice; address internal alice;
address internal bob; address internal bob;
@@ -124,8 +114,24 @@ contract GasTest is Test {
uint256 constant internal INIT_BAL = 1_000_000; // initial token units for each token (internal==amount when base==1) uint256 constant internal INIT_BAL = 1_000_000; // initial token units for each token (internal==amount when base==1)
uint256 constant internal BASE = 1; // use base=1 so internal amounts correspond to raw integers (Q64.64 units) uint256 constant internal BASE = 1; // use base=1 so internal amounts correspond to raw integers (Q64.64 units)
// Compute fixed b from a target slippage profile for a pool that will be initialized
// with numTokens tokens each deposited with INIT_BAL and BASE==1.
function _computeFixedB(uint256 numTokens) internal view returns (int128) {
// Size metric S = sum q_i (in 64.64) with q_i = INIT_BAL for each token (BASE == 1)
int128 S = ABDKMath64x64.fromUInt(numTokens * INIT_BAL);
// E = (1 - s*(n-1)) / (1 + s)
int128 one = ABDKMath64x64.fromInt(1);
int128 nMinus1 = ABDKMath64x64.fromUInt(numTokens - 1);
int128 numerator = one.sub(targetSlippage.mul(nMinus1));
int128 denominator = one.add(targetSlippage);
int128 E = numerator.div(denominator);
// y = -ln(E) / f, b = S / y
int128 y = ABDKMath64x64.ln(E).neg().div(tradeFrac);
return S.div(y);
}
/// @notice Helper function to create a pool with the specified number of _tokens /// @notice Helper function to create a pool with the specified number of _tokens
function createPool(uint256 numTokens) internal returns (IPartyPool) { function createPool(uint256 numTokens) internal returns (PartyPool) {
// Deploy _tokens dynamically // Deploy _tokens dynamically
address[] memory tokens = new address[](numTokens); address[] memory tokens = new address[](numTokens);
uint256[] memory bases = new uint256[](numTokens); uint256[] memory bases = new uint256[](numTokens);
@@ -149,23 +155,23 @@ contract GasTest is Test {
for (uint i = 0; i < tokens.length; i++) { for (uint i = 0; i < tokens.length; i++) {
ierc20Tokens[i] = IERC20(tokens[i]); ierc20Tokens[i] = IERC20(tokens[i]);
} }
// Compute kappa from slippage params and number of _tokens, then construct pool with kappa // Compute fixed b from slippage and expected initial S, then construct pool with fixed b
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage); int128 bFixed = _computeFixedB(ierc20Tokens.length);
PartyPool newPool = Deploy.newPartyPool(address(this), poolName, poolName, ierc20Tokens, bases, bFixed, feePpm, feePpm, false);
uint256[] memory initialBalances = new uint256[](numTokens); // Transfer initial deposit amounts into pool before initial mint
for (uint256 i = 0; i < numTokens; i++) { for (uint256 i = 0; i < numTokens; i++) {
initialBalances[i] = INIT_BAL; TestERC20(tokens[i]).transfer(address(newPool), INIT_BAL);
ierc20Tokens[i].approve(address(planner), INIT_BAL);
} }
vm.prank(planner.owner());
(IPartyPool newPool, ) = planner.newPool(poolName, poolName, ierc20Tokens, computedKappa, feePpm, feePpm, false, // Perform initial mint (initial deposit); receiver is this contract
address(this), address(this), initialBalances, 0, 0); newPool.initialMint(address(this), 0);
return newPool; return newPool;
} }
/// @notice Helper to create a pool with the stable-pair optimization enabled /// @notice Helper to create a pool with the stable-pair optimization enabled
function createPoolStable(uint256 numTokens) internal returns (IPartyPool) { function createPoolStable(uint256 numTokens) internal returns (PartyPool) {
// Deploy _tokens dynamically // Deploy _tokens dynamically
address[] memory tokens = new address[](numTokens); address[] memory tokens = new address[](numTokens);
uint256[] memory bases = new uint256[](numTokens); uint256[] memory bases = new uint256[](numTokens);
@@ -190,8 +196,8 @@ contract GasTest is Test {
for (uint i = 0; i < tokens.length; i++) { for (uint i = 0; i < tokens.length; i++) {
ierc20Tokens[i] = IERC20(tokens[i]); ierc20Tokens[i] = IERC20(tokens[i]);
} }
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(ierc20Tokens.length, tradeFrac, targetSlippage); int128 bFixed = _computeFixedB(ierc20Tokens.length);
IPartyPool newPool = Deploy.newPartyPool(address(this), poolName, poolName, ierc20Tokens, computedKappa, feePpm, feePpm, true); PartyPool newPool = Deploy.newPartyPool(address(this), poolName, poolName, ierc20Tokens, bases, bFixed, feePpm, feePpm, true);
// Transfer initial deposit amounts into pool before initial mint // Transfer initial deposit amounts into pool before initial mint
for (uint256 i = 0; i < numTokens; i++) { for (uint256 i = 0; i < numTokens; i++) {
@@ -237,53 +243,28 @@ contract GasTest is Test {
} }
/// @notice Helper function: perform 10 swaps back-and-forth between the first two _tokens. /// @notice Helper function: perform 10 swaps back-and-forth between the first two _tokens.
function _performSwapGasTest(IPartyPool testPool) internal { function _performSwapGasTest(PartyPool testPool) internal {
_performSwapGasTest(testPool, false);
}
function sendTokensCallback(IERC20 token, uint256 amount) external {
// verify the caller
require(planner.getPoolSupported(msg.sender), 'Not a LiqP pool');
token.transferFrom( alice, msg.sender, amount);
}
function _performSwapGasTest(IPartyPool testPool, bool useCallback) internal {
IERC20[] memory tokens = testPool.allTokens(); IERC20[] memory tokens = testPool.allTokens();
require(tokens.length >= 2, "Pool must have at least 2 tokens"); require(tokens.length >= 2, "Pool must have at least 2 tokens");
address payer;
address spender;
bytes4 selector;
if (useCallback) { // Ensure alice approves pool for both _tokens
payer = address(this);
spender = address(this);
selector = this.sendTokensCallback.selector;
}
else {
payer = alice;
spender = address(testPool);
selector = bytes4(0);
}
vm.prank(alice); vm.prank(alice);
TestERC20(address(tokens[0])).approve(spender, type(uint256).max); TestERC20(address(tokens[0])).approve(address(testPool), type(uint256).max);
vm.prank(alice); vm.prank(alice);
TestERC20(address(tokens[1])).approve(spender, type(uint256).max); TestERC20(address(tokens[1])).approve(address(testPool), type(uint256).max);
uint256 maxIn = 10_000; uint256 maxIn = 1_000;
// Perform swaps alternating directions to avoid large imbalance // Perform 10 swaps alternating directions to avoid large imbalance
for (uint256 i = 0; i < 20; i++) { for (uint256 i = 0; i < 10; i++) {
vm.prank(alice); vm.prank(alice);
if (i % 2 == 0) { if (i % 2 == 0) {
// swap token0 -> token1 // swap token0 -> token1
testPool.swap(payer, selector, alice, 0, 1, maxIn, 0, 0, false); testPool.swap(alice, alice, 0, 1, maxIn, 0, 0, false);
} else { } else {
// swap token1 -> token0 // swap token1 -> token0
testPool.swap(payer, selector, alice, 1, 0, maxIn, 0, 0, false); testPool.swap(alice, alice, 1, 0, maxIn, 0, 0, false);
} }
// shake up the bits
maxIn *= 787;
maxIn /= 1000;
} }
} }
@@ -297,12 +278,6 @@ contract GasTest is Test {
_performSwapGasTest(pool10); _performSwapGasTest(pool10);
} }
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 10-token pool using the callback funding method.
function testSwapGasCallback() public {
_performSwapGasTest(pool10, true);
}
/// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 20-token pool. /// @notice Gas measurement: perform 10 swaps back-and-forth between first two _tokens in the 20-token pool.
function testSwapGasTwenty() public { function testSwapGasTwenty() public {
_performSwapGasTest(pool20); _performSwapGasTest(pool20);
@@ -315,24 +290,24 @@ contract GasTest is Test {
/// @notice Gas measurement: perform 10 swaps back-and-forth on a 2-token stable pair (stable-path enabled) /// @notice Gas measurement: perform 10 swaps back-and-forth on a 2-token stable pair (stable-path enabled)
function testSwapGasStablePair() public { function testSwapGasStablePair() public {
IPartyPool stablePair = createPoolStable(2); PartyPool stablePair = createPoolStable(2);
_performSwapGasTest(stablePair); _performSwapGasTest(stablePair);
} }
/// @notice Gas-style test: alternate swapMint then burnSwap on a 2-token stable pair /// @notice Gas-style test: alternate swapMint then burnSwap on a 2-token stable pair
function testSwapMintBurnSwapGasStablePair() public { function testSwapMintBurnSwapGasStablePair() public {
IPartyPool stablePair = createPoolStable(2); PartyPool stablePair = createPoolStable(2);
_performSwapMintBurnSwapGasTest(stablePair); _performSwapMintBurnSwapGasTest(stablePair);
} }
/// @notice Combined gas test (mint then burn) on 2-token stable pair using mint() and burn(). /// @notice Combined gas test (mint then burn) on 2-token stable pair using mint() and burn().
function testMintBurnGasStablePair() public { function testMintBurnGasStablePair() public {
IPartyPool stablePair = createPoolStable(2); PartyPool stablePair = createPoolStable(2);
_performMintBurnGasTest(stablePair); _performMintBurnGasTest(stablePair);
} }
/// @notice Helper function: alternate swapMint then burnSwap to keep pool size roughly stable. /// @notice Helper function: alternate swapMint then burnSwap to keep pool size roughly stable.
function _performSwapMintBurnSwapGasTest(IPartyPool testPool) internal { function _performSwapMintBurnSwapGasTest(PartyPool testPool) internal {
uint256 iterations = 10; uint256 iterations = 10;
uint256 input = 1_000; uint256 input = 1_000;
IERC20[] memory tokens = testPool.allTokens(); IERC20[] memory tokens = testPool.allTokens();
@@ -345,7 +320,7 @@ contract GasTest is Test {
for (uint256 k = 0; k < iterations; k++) { for (uint256 k = 0; k < iterations; k++) {
// Mint LP by providing single-token input; receive LP minted // Mint LP by providing single-token input; receive LP minted
(, uint256 minted, ) = testPool.swapMint(alice, alice, 0, input, 0); uint256 minted = testPool.swapMint(alice, alice, 0, input, 0);
// If nothing minted (numerical edge), skip burn step // If nothing minted (numerical edge), skip burn step
if (minted == 0) continue; if (minted == 0) continue;
// Immediately burn the minted LP back to _tokens, targeting the same token index // Immediately burn the minted LP back to _tokens, targeting the same token index
@@ -377,7 +352,7 @@ contract GasTest is Test {
/// @notice Helper function: combined gas test (mint then burn) using mint() and burn(). /// @notice Helper function: combined gas test (mint then burn) using mint() and burn().
/// Alternates minting a tiny LP amount and immediately burning the actual minted LP back to avoid net pool depletion. /// Alternates minting a tiny LP amount and immediately burning the actual minted LP back to avoid net pool depletion.
function _performMintBurnGasTest(IPartyPool testPool) internal { function _performMintBurnGasTest(PartyPool testPool) internal {
uint256 iterations = 50; uint256 iterations = 50;
uint256 input = 1_000; uint256 input = 1_000;
IERC20[] memory poolTokens = testPool.allTokens(); IERC20[] memory poolTokens = testPool.allTokens();

View File

@@ -30,7 +30,8 @@ contract LMSRStabilizedTest is Test {
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
q[2] = ABDKMath64x64.fromUInt(1_000_000); q[2] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 b = _computeBFromSlippage(3, q, stdTradeSize, stdSlippage);
s.init(q, b);
} }
function initAlmostBalanced() internal { function initAlmostBalanced() internal {
@@ -38,7 +39,8 @@ contract LMSRStabilizedTest is Test {
q[0] = ABDKMath64x64.fromUInt(999_999); q[0] = ABDKMath64x64.fromUInt(999_999);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
q[2] = ABDKMath64x64.fromUInt(1_000_001); q[2] = ABDKMath64x64.fromUInt(1_000_001);
s.init(q, stdTradeSize, stdSlippage); int128 b = _computeBFromSlippage(3, q, stdTradeSize, stdSlippage);
s.init(q, b);
} }
function initImbalanced() internal { function initImbalanced() internal {
@@ -47,7 +49,8 @@ contract LMSRStabilizedTest is Test {
q[1] = ABDKMath64x64.fromUInt(1e9); q[1] = ABDKMath64x64.fromUInt(1e9);
q[2] = ABDKMath64x64.fromUInt(1); q[2] = ABDKMath64x64.fromUInt(1);
q[3] = ABDKMath64x64.divu(1, 1e9); q[3] = ABDKMath64x64.divu(1, 1e9);
s.init(q, stdTradeSize, stdSlippage); int128 b = _computeBFromSlippage(4, q, stdTradeSize, stdSlippage);
s.init(q, b);
} }
@@ -192,8 +195,7 @@ contract LMSRStabilizedTest is Test {
initAlmostBalanced(); initAlmostBalanced();
// Verify basic state is still functional // Verify basic state is still functional
assertTrue(s.qInternal.length > 0, "State should still be initialized"); assertTrue(s.nAssets > 0, "State should still be initialized");
assertTrue(s.kappa > int128(0), "Kappa should still be positive");
} }
function testRescalingAfterDeposit() public { function testRescalingAfterDeposit() public {
@@ -211,12 +213,10 @@ contract LMSRStabilizedTest is Test {
// Store initial parameters // Store initial parameters
int128 initialB = _computeB(initialQ); int128 initialB = _computeB(initialQ);
int128 initialKappa = s.kappa;
uint256 nAssets = s.qInternal.length;
// Simulate a deposit by increasing all asset quantities by 50% // Simulate a deposit by increasing all asset quantities by 50%
int128[] memory newQ = new int128[](nAssets); int128[] memory newQ = new int128[](s.nAssets);
for (uint i = 0; i < nAssets; i++) { for (uint i = 0; i < s.nAssets; i++) {
// Increase by 50% // Increase by 50%
newQ[i] = initialQ[i].mul(ABDKMath64x64.fromUInt(3).div(ABDKMath64x64.fromUInt(2))); // 1.5x newQ[i] = initialQ[i].mul(ABDKMath64x64.fromUInt(3).div(ABDKMath64x64.fromUInt(2))); // 1.5x
} }
@@ -224,18 +224,15 @@ contract LMSRStabilizedTest is Test {
// Apply the update for proportional change // Apply the update for proportional change
s.updateForProportionalChange(newQ); s.updateForProportionalChange(newQ);
// Verify that b has been rescaled proportionally // Verify that b remains constant after proportional deposit (fixed-b model)
int128 newB = _computeB(s.qInternal); int128 newB = _computeB(s.qInternal);
int128 expectedRatio = ABDKMath64x64.fromUInt(3).div(ABDKMath64x64.fromUInt(2)); // 1.5x int128 expectedRatio = ABDKMath64x64.fromInt(1); // invariant b
int128 actualRatio = newB.div(initialB); int128 actualRatio = newB.div(initialB);
int128 tolerance = ABDKMath64x64.divu(1, 1000); // 0.1% tolerance int128 tolerance = ABDKMath64x64.divu(1, 1000); // 0.1% tolerance
assertTrue((actualRatio.sub(expectedRatio)).abs() < tolerance, "b did not scale proportionally after deposit"); assertTrue((actualRatio.sub(expectedRatio)).abs() < tolerance, "b should remain constant after deposit");
// Verify kappa remained unchanged // Perform a trade and verify outputs are reasonable
assertTrue((s.kappa.sub(initialKappa)).abs() < tolerance, "kappa should not change after deposit");
// Verify slippage target is still met by performing a trade
int128 tradeAmount = s.qInternal[0].mul(stdTradeSize); int128 tradeAmount = s.qInternal[0].mul(stdTradeSize);
(int128 amountIn, int128 amountOut) = s.swapAmountsForExactInput(0, 1, tradeAmount, 0); (int128 amountIn, int128 amountOut) = s.swapAmountsForExactInput(0, 1, tradeAmount, 0);
@@ -251,8 +248,10 @@ contract LMSRStabilizedTest is Test {
int128 slippage = slippageRatio.sub(ABDKMath64x64.fromInt(1)); int128 slippage = slippageRatio.sub(ABDKMath64x64.fromInt(1));
console2.log('post-deposit slippage', slippage); console2.log('post-deposit slippage', slippage);
int128 relativeError = slippage.sub(stdSlippage).abs().div(stdSlippage); // With fixed b, theoretical slippage is exp(a/b) - 1
assertLt(relativeError, ABDKMath64x64.divu(1, 100), "Slippage target not met after deposit"); int128 expectedSlippage = _exp(tradeAmount.div(newB)).sub(ABDKMath64x64.fromInt(1));
int128 slippageError = (slippage.sub(expectedSlippage)).abs();
assertLt(slippageError, ABDKMath64x64.divu(1, 1_000_000), "Observed slippage deviates from model");
} }
/// @notice Test balanced2 handling of limitPrice that causes truncation of input a /// @notice Test balanced2 handling of limitPrice that causes truncation of input a
@@ -261,7 +260,8 @@ contract LMSRStabilizedTest is Test {
int128[] memory q = new int128[](2); int128[] memory q = new int128[](2);
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 bInit = _computeBFromSlippage(2, q, stdTradeSize, stdSlippage);
s.init(q, bInit);
// Compute b for constructing meaningful a and limits // Compute b for constructing meaningful a and limits
int128 b = _computeB(q); int128 b = _computeB(q);
@@ -297,7 +297,8 @@ contract LMSRStabilizedTest is Test {
int128[] memory q = new int128[](2); int128[] memory q = new int128[](2);
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 bInit = _computeBFromSlippage(2, q, stdTradeSize, stdSlippage);
s.init(q, bInit);
// Small input a // Small input a
int128 a = q[0].mul(ABDKMath64x64.divu(1, 1000)); // 0.1% of asset int128 a = q[0].mul(ABDKMath64x64.divu(1, 1000)); // 0.1% of asset
@@ -327,7 +328,8 @@ contract LMSRStabilizedTest is Test {
int128[] memory q = new int128[](2); int128[] memory q = new int128[](2);
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 bInit = _computeBFromSlippage(2, q, stdTradeSize, stdSlippage);
s.init(q, bInit);
int128 limitPrice = ABDKMath64x64.fromInt(1); // equal to current price int128 limitPrice = ABDKMath64x64.fromInt(1); // equal to current price
@@ -360,12 +362,10 @@ contract LMSRStabilizedTest is Test {
// Store initial parameters // Store initial parameters
int128 initialB = _computeB(initialQ); int128 initialB = _computeB(initialQ);
int128 initialKappa = s.kappa;
// Simulate a withdrawal by decreasing all asset quantities by 30% // Simulate a withdrawal by decreasing all asset quantities by 30%
uint256 nAssets = s.qInternal.length; int128[] memory newQ = new int128[](s.nAssets);
int128[] memory newQ = new int128[](nAssets); for (uint i = 0; i < s.nAssets; i++) {
for (uint i = 0; i < nAssets; i++) {
// Decrease by 30% // Decrease by 30%
newQ[i] = initialQ[i].mul(ABDKMath64x64.fromUInt(7).div(ABDKMath64x64.fromUInt(10))); // 0.7x newQ[i] = initialQ[i].mul(ABDKMath64x64.fromUInt(7).div(ABDKMath64x64.fromUInt(10))); // 0.7x
} }
@@ -373,18 +373,15 @@ contract LMSRStabilizedTest is Test {
// Apply the update for proportional change // Apply the update for proportional change
s.updateForProportionalChange(newQ); s.updateForProportionalChange(newQ);
// Verify that b has been rescaled proportionally // Verify that b remains constant after proportional withdrawal (fixed-b model)
int128 newB = _computeB(s.qInternal); int128 newB = _computeB(s.qInternal);
int128 expectedRatio = ABDKMath64x64.fromUInt(7).div(ABDKMath64x64.fromUInt(10)); // 0.7x int128 expectedRatio = ABDKMath64x64.fromInt(1); // invariant b
int128 actualRatio = newB.div(initialB); int128 actualRatio = newB.div(initialB);
int128 tolerance = ABDKMath64x64.divu(1, 1000); // 0.1% tolerance int128 tolerance = ABDKMath64x64.divu(1, 1000); // 0.1% tolerance
assertTrue((actualRatio.sub(expectedRatio)).abs() < tolerance, "b did not scale proportionally after withdrawal"); assertTrue((actualRatio.sub(expectedRatio)).abs() < tolerance, "b should remain constant after withdrawal");
// Verify kappa remained unchanged // Perform a trade and verify outputs are reasonable
assertTrue((s.kappa.sub(initialKappa)).abs() < tolerance, "kappa should not change after withdrawal");
// Verify slippage target is still met by performing a trade
int128 tradeAmount = s.qInternal[0].mul(stdTradeSize); int128 tradeAmount = s.qInternal[0].mul(stdTradeSize);
(int128 amountIn, int128 amountOut) = s.swapAmountsForExactInput(0, 1, tradeAmount, 0); (int128 amountIn, int128 amountOut) = s.swapAmountsForExactInput(0, 1, tradeAmount, 0);
@@ -400,8 +397,10 @@ contract LMSRStabilizedTest is Test {
int128 slippage = slippageRatio.sub(ABDKMath64x64.fromInt(1)); int128 slippage = slippageRatio.sub(ABDKMath64x64.fromInt(1));
console2.log('post-withdrawal slippage', slippage); console2.log('post-withdrawal slippage', slippage);
int128 relativeError = slippage.sub(stdSlippage).abs().div(stdSlippage); // With fixed b, theoretical slippage is exp(a/b) - 1
assertLt(relativeError, ABDKMath64x64.divu(1, 100), "Slippage target not met after withdrawal"); int128 expectedSlippage = _exp(tradeAmount.div(newB)).sub(ABDKMath64x64.fromInt(1));
int128 slippageError = (slippage.sub(expectedSlippage)).abs();
assertLt(slippageError, ABDKMath64x64.divu(1, 1_000_000), "Observed slippage deviates from model");
} }
// --- tests probing numerical stability and boundary conditions --- // --- tests probing numerical stability and boundary conditions ---
@@ -410,7 +409,7 @@ contract LMSRStabilizedTest is Test {
function testRecenterShiftTooLargeReverts() public { function testRecenterShiftTooLargeReverts() public {
initAlmostBalanced(); initAlmostBalanced();
// Recentering has been removed, so this test now just verifies basic functionality // Recentering has been removed, so this test now just verifies basic functionality
assertTrue(s.qInternal.length > 0, "State should still be initialized"); assertTrue(s.nAssets > 0, "State should still be initialized");
} }
/// @notice limitPrice <= current price should revert (no partial fill) /// @notice limitPrice <= current price should revert (no partial fill)
@@ -433,6 +432,27 @@ contract LMSRStabilizedTest is Test {
this.externalSwapAmountsForExactInput(0, 1, tradeAmount, ABDKMath64x64.fromInt(1)); this.externalSwapAmountsForExactInput(0, 1, tradeAmount, ABDKMath64x64.fromInt(1));
} }
/// @notice If q_j == 0, kernel should still handle computation without revert (wrapper enforces caps)
function testZeroQuantityOutputAssetDoesNotRevert() public {
initBalanced();
// Create mock qInternal where asset 1 has zero quantity
int128[] memory mockQInternal = new int128[](3);
mockQInternal[0] = ABDKMath64x64.fromUInt(1_000_000);
mockQInternal[1] = int128(0); // Zero quantity for asset 1
mockQInternal[2] = ABDKMath64x64.fromUInt(1_000_000);
// Update the state's cached qInternal
_updateCachedQInternal(mockQInternal);
int128 tradeAmount = mockQInternal[0].mul(stdTradeSize);
// Should not revert; exact-input uses full input and returns a defined output
(int128 usedIn, int128 outAmt) = this.externalSwapAmountsForExactInput(0, 1, tradeAmount, 0);
assertEq(usedIn, tradeAmount, "exact-input should consume full input without limit");
assertTrue(outAmt >= 0, "output amount should be non-negative when q_j == 0");
}
/// @notice swapAmountsForPriceLimit returns zero if limit equals current price /// @notice swapAmountsForPriceLimit returns zero if limit equals current price
function testSwapAmountsForPriceLimitZeroWhenLimitEqualsPrice() public { function testSwapAmountsForPriceLimitZeroWhenLimitEqualsPrice() public {
initBalanced(); initBalanced();
@@ -517,18 +537,16 @@ contract LMSRStabilizedTest is Test {
this.externalSwapAmountsForExactInput(0, 1, a, 0); this.externalSwapAmountsForExactInput(0, 1, a, 0);
} }
// Helper function to compute b from qInternal (either from provided array or state) // Helper function to fetch fixed b (independent of qInternal)
function _computeB(int128[] memory qInternal) internal view returns (int128) { function _computeB(int128[] memory qInternal) internal view returns (int128) {
int128 sizeMetric = _computeSizeMetric(qInternal); // silence unused warning for qInternal in tests
require(sizeMetric > int128(0), "LMSR: size metric zero"); qInternal;
return s.kappa.mul(sizeMetric); return s.bFixed;
} }
// Overload that uses state's cached qInternal // Overload that uses state's fixed b
function _computeB() internal view returns (int128) { function _computeB() internal view returns (int128) {
int128 sizeMetric = _computeSizeMetric(s.qInternal); return s.bFixed;
require(sizeMetric > int128(0), "LMSR: size metric zero");
return s.kappa.mul(sizeMetric);
} }
// Helper function to compute size metric (sum of all asset quantities) // Helper function to compute size metric (sum of all asset quantities)
@@ -541,6 +559,41 @@ contract LMSRStabilizedTest is Test {
return total; return total;
} }
// Local helper: compute fixed b from a target slippage profile.
// For a trade of fraction f of S with target slippage s across n assets:
// E = (1 - s*(n-1)) / (1 + s)
// y = -ln(E) / f
// b = S / y
function _computeBFromSlippage(
uint256 nAssets,
int128[] memory qInternal,
int128 tradeFrac,
int128 targetSlippage
) internal pure returns (int128) {
require(nAssets > 1, "test: n>1");
int128 S = _computeSizeMetric(qInternal);
require(S > int128(0), "test: S<=0");
int128 f = tradeFrac;
require(f > int128(0) && f < ABDKMath64x64.fromInt(1), "test: f out of range");
int128 one = ABDKMath64x64.fromInt(1);
int128 nMinus1 = ABDKMath64x64.fromUInt(nAssets - 1);
// E must be in (0,1)
int128 numerator = one.sub(targetSlippage.mul(nMinus1)); // 1 - s*(n-1)
int128 denominator = one.add(targetSlippage); // 1 + s
require(numerator > int128(0), "test: bad slippage");
int128 E = numerator.div(denominator);
require(E > int128(0) && E < one, "test: E out of range");
int128 y = ABDKMath64x64.ln(E).neg().div(f);
require(y > int128(0), "test: y<=0");
return S.div(y);
}
// Helper function to update the state's cached qInternal // Helper function to update the state's cached qInternal
function _updateCachedQInternal(int128[] memory mockQInternal) internal { function _updateCachedQInternal(int128[] memory mockQInternal) internal {
// First ensure qInternal array exists with the right size // First ensure qInternal array exists with the right size
@@ -676,8 +729,7 @@ contract LMSRStabilizedTest is Test {
initBalanced(); initBalanced();
// Create initial quantities // Create initial quantities
uint256 nAssets = s.qInternal.length; int128[] memory initialQValues = new int128[](s.nAssets);
int128[] memory initialQValues = new int128[](nAssets);
initialQValues[0] = ABDKMath64x64.fromUInt(1_000_000); initialQValues[0] = ABDKMath64x64.fromUInt(1_000_000);
initialQValues[1] = ABDKMath64x64.fromUInt(1_000_000); initialQValues[1] = ABDKMath64x64.fromUInt(1_000_000);
initialQValues[2] = ABDKMath64x64.fromUInt(1_000_000); initialQValues[2] = ABDKMath64x64.fromUInt(1_000_000);
@@ -689,8 +741,8 @@ contract LMSRStabilizedTest is Test {
int128 directSwapAmount = initialQValues[0].mul(stdTradeSize); int128 directSwapAmount = initialQValues[0].mul(stdTradeSize);
// Store a backup of the original values to restore between swaps // Store a backup of the original values to restore between swaps
int128[] memory backupQ = new int128[](nAssets); int128[] memory backupQ = new int128[](s.nAssets);
for (uint i = 0; i < nAssets; i++) { for (uint i = 0; i < s.nAssets; i++) {
backupQ[i] = s.qInternal[i]; backupQ[i] = s.qInternal[i];
} }
@@ -782,9 +834,8 @@ contract LMSRStabilizedTest is Test {
int128 tradeAmount1 = s.qInternal[1].mul(tradeSize); int128 tradeAmount1 = s.qInternal[1].mul(tradeSize);
// Store original state to restore between tests // Store original state to restore between tests
uint256 nAssets = s.qInternal.length; int128[] memory backupQ = new int128[](s.nAssets);
int128[] memory backupQ = new int128[](nAssets); for (uint i = 0; i < s.nAssets; i++) {
for (uint i = 0; i < nAssets; i++) {
backupQ[i] = s.qInternal[i]; backupQ[i] = s.qInternal[i];
} }
@@ -900,7 +951,7 @@ contract LMSRStabilizedTest is Test {
int128 alpha = ABDKMath64x64.divu(1, 100); // 1% int128 alpha = ABDKMath64x64.divu(1, 100); // 1%
int128 S = _computeSizeMetric(s.qInternal); int128 S = _computeSizeMetric(s.qInternal);
(int128 burned, int128 payout) = s.swapAmountsForBurn(0, alpha); (int128 payout, int128 burned) = s.swapAmountsForBurn(0, alpha);
// burned should equal alpha * S // burned should equal alpha * S
assertEq(burned, alpha.mul(S), "burned size-metric mismatch"); assertEq(burned, alpha.mul(S), "burned size-metric mismatch");
@@ -921,7 +972,7 @@ contract LMSRStabilizedTest is Test {
_updateCachedQInternal(mockQInternal); _updateCachedQInternal(mockQInternal);
int128 alpha = ABDKMath64x64.divu(1, 100); // 1% int128 alpha = ABDKMath64x64.divu(1, 100); // 1%
(int128 burned, int128 payout) = s.swapAmountsForBurn(0, alpha); (int128 payout, int128 burned) = s.swapAmountsForBurn(0, alpha);
// Should still burn the size metric // Should still burn the size metric
int128 S = _computeSizeMetric(mockQInternal); int128 S = _computeSizeMetric(mockQInternal);
@@ -940,7 +991,8 @@ contract LMSRStabilizedTest is Test {
int128[] memory q = new int128[](2); int128[] memory q = new int128[](2);
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 bInit = _computeBFromSlippage(2, q, stdTradeSize, stdSlippage);
s.init(q, bInit);
// Small trade (well within u <= 0.5 and delta <= 1%) // Small trade (well within u <= 0.5 and delta <= 1%)
int128 a = q[0].mul(ABDKMath64x64.divu(1, 1000)); // 0.1% of asset int128 a = q[0].mul(ABDKMath64x64.divu(1, 1000)); // 0.1% of asset
@@ -971,7 +1023,8 @@ contract LMSRStabilizedTest is Test {
int128[] memory q = new int128[](2); int128[] memory q = new int128[](2);
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 bInit = _computeBFromSlippage(2, q, stdTradeSize, stdSlippage);
s.init(q, bInit);
// Prepare newQ starting from equal quantities; we'll grow q0 until delta > DELTA_MAX // Prepare newQ starting from equal quantities; we'll grow q0 until delta > DELTA_MAX
int128[] memory newQ = new int128[](2); int128[] memory newQ = new int128[](2);
@@ -1030,7 +1083,8 @@ contract LMSRStabilizedTest is Test {
int128[] memory q = new int128[](2); int128[] memory q = new int128[](2);
q[0] = ABDKMath64x64.fromUInt(1_000_000); q[0] = ABDKMath64x64.fromUInt(1_000_000);
q[1] = ABDKMath64x64.fromUInt(1_000_000); q[1] = ABDKMath64x64.fromUInt(1_000_000);
s.init(q, stdTradeSize, stdSlippage); int128 bInit = _computeBFromSlippage(2, q, stdTradeSize, stdSlippage);
s.init(q, bInit);
// Compute b // Compute b
int128 b = _computeB(q); int128 b = _computeB(q);

View File

@@ -1,21 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.30;
import {IERC3156FlashBorrower} from "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
import {IERC20} from "../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
// Minimal flash borrower that repays amount + fee back to the pool passed via data
contract MockFlashBorrower is IERC3156FlashBorrower {
// IERC3156FlashBorrower callback
function onFlashLoan(
address /*initiator*/,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32) {
address poolAddr = abi.decode(data, (address));
IERC20(token).approve(poolAddr, amount + fee);
return keccak256("ERC3156FlashBorrower.onFlashLoan");
}
}

View File

@@ -10,7 +10,7 @@ import "../src/PartyPool.sol";
import {NativeWrapper} from "../src/NativeWrapper.sol"; import {NativeWrapper} from "../src/NativeWrapper.sol";
import {PartyPlanner} from "../src/PartyPlanner.sol"; import {PartyPlanner} from "../src/PartyPlanner.sol";
import {Deploy} from "./Deploy.sol"; import {Deploy} from "./Deploy.sol";
import {PartyInfo} from "../src/PartyInfo.sol"; import {PartyPoolViewer} from "../src/PartyPoolViewer.sol";
import {WETH9} from "./WETH9.sol"; import {WETH9} from "./WETH9.sol";
/// @notice Minimal ERC20 token for tests with an external mint function. /// @notice Minimal ERC20 token for tests with an external mint function.
@@ -41,7 +41,7 @@ contract NativeTest is Test {
TestERC20Native token1; TestERC20Native token1;
WETH9 weth; // WETH is our third token WETH9 weth; // WETH is our third token
PartyPool pool; PartyPool pool;
PartyInfo info; PartyPoolViewer viewer;
address alice; address alice;
address bob; address bob;
@@ -53,6 +53,18 @@ contract NativeTest is Test {
uint256 constant INIT_BAL = 1_000_000; // initial token units for each token uint256 constant INIT_BAL = 1_000_000; // initial token units for each token
uint256 constant BASE = 1; // use base=1 so internal amounts correspond to raw integers uint256 constant BASE = 1; // use base=1 so internal amounts correspond to raw integers
// Compute fixed b for a pool initialized with numTokens tokens, each deposited with INIT_BAL (BASE == 1).
function _computeFixedB(uint256 numTokens) internal view returns (int128) {
int128 S = ABDKMath64x64.fromUInt(numTokens * INIT_BAL);
int128 one = ABDKMath64x64.fromInt(1);
int128 nMinus1 = ABDKMath64x64.fromUInt(numTokens - 1);
int128 numerator = one.sub(targetSlippage.mul(nMinus1));
int128 denominator = one.add(targetSlippage);
int128 E = numerator.div(denominator);
int128 y = ABDKMath64x64.ln(E).neg().div(tradeFrac);
return S.div(y);
}
function setUp() public { function setUp() public {
alice = address(0xA11ce); alice = address(0xA11ce);
bob = address(0xB0b); bob = address(0xB0b);
@@ -93,8 +105,8 @@ contract NativeTest is Test {
// Deploy pool with a small fee (0.1%) // Deploy pool with a small fee (0.1%)
uint256 feePpm = 1000; uint256 feePpm = 1000;
int128 kappa = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 bFixed = _computeFixedB(tokens.length);
pool = Deploy.newPartyPool(address(this), "LP", "LP", tokens, kappa, feePpm, feePpm, weth, false); pool = Deploy.newPartyPool(address(this), "LP", "LP", tokens, bases, bFixed, feePpm, feePpm, weth, false);
// Transfer initial deposit amounts into pool // Transfer initial deposit amounts into pool
token0.transfer(address(pool), INIT_BAL); token0.transfer(address(pool), INIT_BAL);
@@ -111,7 +123,7 @@ contract NativeTest is Test {
token0.mint(bob, INIT_BAL); token0.mint(bob, INIT_BAL);
token1.mint(bob, INIT_BAL); token1.mint(bob, INIT_BAL);
info = Deploy.newInfo(); viewer = Deploy.newViewer();
} }
/// @notice Helper to verify refunds work correctly /// @notice Helper to verify refunds work correctly
@@ -142,7 +154,6 @@ contract NativeTest is Test {
// Send native currency with {value: maxIn} // Send native currency with {value: maxIn}
(uint256 amountIn, uint256 amountOut, ) = pool.swap{value: maxIn}( (uint256 amountIn, uint256 amountOut, ) = pool.swap{value: maxIn}(
alice, // payer alice, // payer
bytes4(0),
alice, // receiver alice, // receiver
2, // inputTokenIndex (WETH) 2, // inputTokenIndex (WETH)
0, // outputTokenIndex (token0) 0, // outputTokenIndex (token0)
@@ -180,7 +191,6 @@ contract NativeTest is Test {
// Execute swap: token0 (index 0) -> WETH (index 2) with unwrap=true // Execute swap: token0 (index 0) -> WETH (index 2) with unwrap=true
(uint256 amountIn, uint256 amountOut, ) = pool.swap( (uint256 amountIn, uint256 amountOut, ) = pool.swap(
alice, // payer alice, // payer
bytes4(0), // no selector: use ERC20 approvals
alice, // receiver alice, // receiver
0, // inputTokenIndex (token0) 0, // inputTokenIndex (token0)
2, // outputTokenIndex (WETH) 2, // outputTokenIndex (WETH)
@@ -216,7 +226,6 @@ contract NativeTest is Test {
// Execute swap with excess native currency // Execute swap with excess native currency
(uint256 amountIn, , ) = pool.swap{value: totalSent}( (uint256 amountIn, , ) = pool.swap{value: totalSent}(
alice, // payer alice, // payer
bytes4(0),
alice, // receiver alice, // receiver
2, // inputTokenIndex (WETH) 2, // inputTokenIndex (WETH)
0, // outputTokenIndex (token0) 0, // outputTokenIndex (token0)
@@ -303,7 +312,7 @@ contract NativeTest is Test {
uint256 lpRequest = pool.totalSupply() / 10; // Request 10% of pool uint256 lpRequest = pool.totalSupply() / 10; // Request 10% of pool
// Get required deposit amounts // Get required deposit amounts
uint256[] memory deposits = info.mintAmounts(pool, lpRequest); uint256[] memory deposits = viewer.mintAmounts(pool, lpRequest);
vm.startPrank(alice); vm.startPrank(alice);
token0.approve(address(pool), type(uint256).max); token0.approve(address(pool), type(uint256).max);
@@ -332,7 +341,7 @@ contract NativeTest is Test {
/// @notice Test mint with excess native currency - verify refund /// @notice Test mint with excess native currency - verify refund
function testMintWithExcessNativeRefunded() public { function testMintWithExcessNativeRefunded() public {
uint256 lpRequest = pool.totalSupply() / 10; uint256 lpRequest = pool.totalSupply() / 10;
uint256[] memory deposits = info.mintAmounts(pool, lpRequest); uint256[] memory deposits = viewer.mintAmounts(pool, lpRequest);
vm.startPrank(alice); vm.startPrank(alice);
token0.approve(address(pool), type(uint256).max); token0.approve(address(pool), type(uint256).max);
@@ -368,7 +377,7 @@ contract NativeTest is Test {
uint256 lpToBurn = pool.totalSupply() / 10; uint256 lpToBurn = pool.totalSupply() / 10;
// Get expected withdraw amounts // Get expected withdraw amounts
uint256[] memory withdraws = info.burnAmounts(pool, lpToBurn); uint256[] memory withdraws = viewer.burnAmounts(pool, lpToBurn);
uint256 thisEthBefore = address(this).balance; uint256 thisEthBefore = address(this).balance;
uint256 expectedWethWithdraw = withdraws[2]; // WETH is index 2 uint256 expectedWethWithdraw = withdraws[2]; // WETH is index 2
@@ -394,7 +403,7 @@ contract NativeTest is Test {
/// @notice Test burn to a different receiver with native output /// @notice Test burn to a different receiver with native output
function testBurnToReceiverWithNativeOutput() public { function testBurnToReceiverWithNativeOutput() public {
uint256 lpToBurn = pool.totalSupply() / 10; uint256 lpToBurn = pool.totalSupply() / 10;
uint256[] memory withdraws = info.burnAmounts(pool, lpToBurn); uint256[] memory withdraws = viewer.burnAmounts(pool, lpToBurn);
uint256 bobEthBefore = bob.balance; uint256 bobEthBefore = bob.balance;
uint256 bobToken0Before = token0.balanceOf(bob); uint256 bobToken0Before = token0.balanceOf(bob);
@@ -429,7 +438,7 @@ contract NativeTest is Test {
uint256 aliceLpBefore = pool.balanceOf(alice); uint256 aliceLpBefore = pool.balanceOf(alice);
// Call swapMint with native currency: deposit ETH as WETH (index 2) // Call swapMint with native currency: deposit ETH as WETH (index 2)
(, uint256 lpMinted,) = pool.swapMint{value: maxIn}( uint256 lpMinted = pool.swapMint{value: maxIn}(
alice, // payer alice, // payer
alice, // receiver alice, // receiver
2, // inputTokenIndex (WETH) 2, // inputTokenIndex (WETH)
@@ -460,7 +469,7 @@ contract NativeTest is Test {
uint256 aliceEthBefore = alice.balance; uint256 aliceEthBefore = alice.balance;
// Send excess native currency // Send excess native currency
(, uint256 lpMinted,) = pool.swapMint{value: totalSent}( uint256 lpMinted = pool.swapMint{value: totalSent}(
alice, alice,
alice, alice,
2, // WETH 2, // WETH
@@ -487,7 +496,7 @@ contract NativeTest is Test {
uint256 thisEthBefore = address(this).balance; uint256 thisEthBefore = address(this).balance;
// Burn LP and receive all proceeds as native currency (WETH unwrapped) // Burn LP and receive all proceeds as native currency (WETH unwrapped)
(uint256 payout, ) = pool.burnSwap( uint256 payout = pool.burnSwap(
address(this), // payer (holds LP) address(this), // payer (holds LP)
address(this), // receiver address(this), // receiver
lpToBurn, // lpAmount lpToBurn, // lpAmount
@@ -509,7 +518,7 @@ contract NativeTest is Test {
uint256 bobEthBefore = bob.balance; uint256 bobEthBefore = bob.balance;
// Burn LP and send native currency to bob // Burn LP and send native currency to bob
(uint256 payout, ) = pool.burnSwap( uint256 payout = pool.burnSwap(
address(this), // payer address(this), // payer
bob, // receiver bob, // receiver
lpToBurn, lpToBurn,
@@ -534,7 +543,7 @@ contract NativeTest is Test {
// 1. Mint with native currency // 1. Mint with native currency
uint256 lpRequest = pool.totalSupply() / 20; // 5% of pool uint256 lpRequest = pool.totalSupply() / 20; // 5% of pool
uint256[] memory deposits = info.mintAmounts(pool, lpRequest); uint256[] memory deposits = viewer.mintAmounts(pool, lpRequest);
token0.approve(address(pool), type(uint256).max); token0.approve(address(pool), type(uint256).max);
token1.approve(address(pool), type(uint256).max); token1.approve(address(pool), type(uint256).max);
@@ -545,20 +554,20 @@ contract NativeTest is Test {
// 2. Swap native currency for token0 // 2. Swap native currency for token0
uint256 swapAmount = 5_000; uint256 swapAmount = 5_000;
(, uint256 amountOut, ) = pool.swap{value: swapAmount}( (, uint256 amountOut, ) = pool.swap{value: swapAmount}(
alice,bytes4(0),alice, 2, 0, swapAmount, 0, 0, false alice, alice, 2, 0, swapAmount, 0, 0, false
); );
assertTrue(amountOut > 0, "Should receive token0"); assertTrue(amountOut > 0, "Should receive token0");
// 3. Swap token0 back to native currency // 3. Swap token0 back to native currency
uint256 token0Balance = token0.balanceOf(alice); uint256 token0Balance = token0.balanceOf(alice);
(, uint256 swapOut2, ) = pool.swap( (, uint256 swapOut2, ) = pool.swap(
alice, bytes4(0), alice, 0, 2, token0Balance / 2, 0, 0, true alice, alice, 0, 2, token0Balance / 2, 0, 0, true
); );
assertTrue(swapOut2 > 0, "Should receive native currency"); assertTrue(swapOut2 > 0, "Should receive native currency");
// 4. Burn LP to native currency // 4. Burn LP to native currency
uint256 lpToBurn = lpMinted / 2; uint256 lpToBurn = lpMinted / 2;
(uint256 payout, ) = pool.burnSwap(alice, alice, lpToBurn, 2, 0, true); uint256 payout = pool.burnSwap(alice, alice, lpToBurn, 2, 0, true);
assertTrue(payout > 0, "Should receive payout in native"); assertTrue(payout > 0, "Should receive payout in native");
// Alice should have some ETH back (maybe more or less depending on slippage) // Alice should have some ETH back (maybe more or less depending on slippage)
@@ -579,7 +588,7 @@ contract NativeTest is Test {
// Swap token0 -> WETH without unwrap // Swap token0 -> WETH without unwrap
(, uint256 amountOut, ) = pool.swap( (, uint256 amountOut, ) = pool.swap(
alice, bytes4(0), alice, 0, 2, maxIn, 0, 0, false // unwrap=false alice, alice, 0, 2, maxIn, 0, 0, false // unwrap=false
); );
assertTrue(amountOut > 0, "Should receive WETH tokens"); assertTrue(amountOut > 0, "Should receive WETH tokens");
@@ -600,7 +609,7 @@ contract NativeTest is Test {
// Try to swap token0 (not WETH) by sending native currency - should revert // Try to swap token0 (not WETH) by sending native currency - should revert
vm.expectRevert(); vm.expectRevert();
pool.swap{value: 10_000}( pool.swap{value: 10_000}(
alice, bytes4(0), alice, 0, 1, 10_000, 0, 0, false alice, alice, 0, 1, 10_000, 0, 0, false
); );
vm.stopPrank(); vm.stopPrank();

View File

@@ -15,6 +15,7 @@ import {LMSRStabilized} from "../src/LMSRStabilized.sol";
import {PartyPlanner} from "../src/PartyPlanner.sol"; import {PartyPlanner} from "../src/PartyPlanner.sol";
import {PartyPool} from "../src/PartyPool.sol"; import {PartyPool} from "../src/PartyPool.sol";
import {MockERC20} from "./PartyPlanner.t.sol"; import {MockERC20} from "./PartyPlanner.t.sol";
import "@abdk/ABDKMath64x64.sol";
// Mock ERC20 token for testing // Mock ERC20 token for testing
contract MockERC20 is ERC20 { contract MockERC20 is ERC20 {
@@ -34,11 +35,37 @@ contract MockERC20 is ERC20 {
} }
contract PartyPlannerTest is Test { contract PartyPlannerTest is Test {
using ABDKMath64x64 for int128;
PartyPlanner public planner; PartyPlanner public planner;
MockERC20 public tokenA; MockERC20 public tokenA;
MockERC20 public tokenB; MockERC20 public tokenB;
MockERC20 public tokenC; MockERC20 public tokenC;
function _computeFixedBFromDeposits(
uint256 nAssets,
uint256[] memory bases,
uint256[] memory initialDeposits,
int128 tradeFrac,
int128 targetSlippage
) internal pure returns (int128) {
require(bases.length == initialDeposits.length && bases.length == nAssets, "length mismatch");
// Compute S = sum(deposit_i / base_i) in Q64.64
int128 S = 0;
for (uint256 i = 0; i < nAssets; i++) {
S = S + ABDKMath64x64.divu(initialDeposits[i], bases[i]);
}
// E = (1 - s*(n-1)) / (1 + s)
int128 one = ABDKMath64x64.fromInt(1);
int128 nMinus1 = ABDKMath64x64.fromUInt(nAssets - 1);
int128 numerator = one.sub(targetSlippage.mul(nMinus1));
int128 denominator = one.add(targetSlippage);
int128 E = numerator.div(denominator);
// y = -ln(E) / f, b = S / y
int128 y = ABDKMath64x64.ln(E).neg().div(tradeFrac);
return S.div(y);
}
address public payer = makeAddr("payer"); address public payer = makeAddr("payer");
address public receiver = makeAddr("receiver"); address public receiver = makeAddr("receiver");
@@ -93,14 +120,15 @@ contract PartyPlannerTest is Test {
uint256 initialTokenACount = planner.poolsByTokenCount(IERC20(address(tokenA))); uint256 initialTokenACount = planner.poolsByTokenCount(IERC20(address(tokenA)));
uint256 initialTokenBCount = planner.poolsByTokenCount(IERC20(address(tokenB))); uint256 initialTokenBCount = planner.poolsByTokenCount(IERC20(address(tokenB)));
// Compute kappa then create pool via kappa overload // Compute fixed b from slippage and initial deposits, then create pool
int128 computedKappa = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 bFixed = _computeFixedBFromDeposits(tokens.length, bases, initialDeposits, tradeFrac, targetSlippage);
(IPartyPool pool, uint256 lpAmount) = planner.newPool( (IPartyPool pool, uint256 lpAmount) = planner.newPool(
name, name,
symbol, symbol,
tokens, tokens,
computedKappa, bases,
bFixed,
swapFeePpm, swapFeePpm,
flashFeePpm, flashFeePpm,
false, // not stable false, // not stable
@@ -173,10 +201,10 @@ contract PartyPlannerTest is Test {
deposits1[0] = INITIAL_DEPOSIT_AMOUNT; deposits1[0] = INITIAL_DEPOSIT_AMOUNT;
deposits1[1] = INITIAL_DEPOSIT_AMOUNT; deposits1[1] = INITIAL_DEPOSIT_AMOUNT;
int128 kappa1 = LMSRStabilized.computeKappaFromSlippage(tokens1.length, int128((1 << 64) - 1), int128(1 << 62)); int128 b1 = _computeFixedBFromDeposits(tokens1.length, bases1, deposits1, int128((1 << 64) - 1), int128(1 << 62));
(IPartyPool pool1,) = planner.newPool( (IPartyPool pool1,) = planner.newPool(
"Pool 1", "LP1", tokens1, "Pool 1", "LP1", tokens1, bases1,
kappa1, 3000, 5000, false, b1, 3000, 5000, false,
payer, receiver, deposits1, 1000e18, 0 payer, receiver, deposits1, 1000e18, 0
); );
@@ -193,10 +221,10 @@ contract PartyPlannerTest is Test {
deposits2[0] = INITIAL_DEPOSIT_AMOUNT; deposits2[0] = INITIAL_DEPOSIT_AMOUNT;
deposits2[1] = INITIAL_DEPOSIT_AMOUNT / 1e12; // Adjust for 6 decimals deposits2[1] = INITIAL_DEPOSIT_AMOUNT / 1e12; // Adjust for 6 decimals
int128 kappa2 = LMSRStabilized.computeKappaFromSlippage(tokens2.length, int128((1 << 64) - 1), int128(1 << 62)); int128 b2 = _computeFixedBFromDeposits(tokens2.length, bases2, deposits2, int128((1 << 64) - 1), int128(1 << 62));
(IPartyPool pool2,) = planner.newPool( (IPartyPool pool2,) = planner.newPool(
"Pool 2", "LP2", tokens2, "Pool 2", "LP2", tokens2, bases2,
kappa2, 3000, 5000, false, b2, 3000, 5000, false,
payer, receiver, deposits2, 1000e18, 0 payer, receiver, deposits2, 1000e18, 0
); );
@@ -239,7 +267,7 @@ contract PartyPlannerTest is Test {
vm.expectRevert("Planner: tokens and deposits length mismatch"); vm.expectRevert("Planner: tokens and deposits length mismatch");
// call old-signature convenience (it will still exist) for the mismatched-length revert check // call old-signature convenience (it will still exist) for the mismatched-length revert check
planner.newPool( planner.newPool(
"Test Pool", "TESTLP", tokens, "Test Pool", "TESTLP", tokens, bases,
int128((1 << 64) - 1), int128(1 << 62), 3000, 5000, false, int128((1 << 64) - 1), int128(1 << 62), 3000, 5000, false,
payer, receiver, deposits, 1000e18, 0 payer, receiver, deposits, 1000e18, 0
); );
@@ -249,31 +277,31 @@ contract PartyPlannerTest is Test {
validDeposits[0] = INITIAL_DEPOSIT_AMOUNT; validDeposits[0] = INITIAL_DEPOSIT_AMOUNT;
validDeposits[1] = INITIAL_DEPOSIT_AMOUNT; validDeposits[1] = INITIAL_DEPOSIT_AMOUNT;
int128 kappaErr = LMSRStabilized.computeKappaFromSlippage(tokens.length, int128((1 << 64) - 1), int128(1 << 62)); int128 bErr = _computeFixedBFromDeposits(tokens.length, bases, validDeposits, int128((1 << 64) - 1), int128(1 << 62));
vm.expectRevert("Planner: payer cannot be zero address"); vm.expectRevert("Planner: payer cannot be zero address");
planner.newPool( planner.newPool(
"Test Pool", "TESTLP", tokens, "Test Pool", "TESTLP", tokens, bases,
kappaErr, 3000, 5000, false, bErr, 3000, 5000, false,
address(0), receiver, validDeposits, 1000e18, 0 address(0), receiver, validDeposits, 1000e18, 0
); );
// Test zero receiver address // Test zero receiver address
vm.expectRevert("Planner: receiver cannot be zero address"); vm.expectRevert("Planner: receiver cannot be zero address");
planner.newPool( planner.newPool(
"Test Pool", "TESTLP", tokens, "Test Pool", "TESTLP", tokens, bases,
kappaErr, 3000, 5000, false, bErr, 3000, 5000, false,
payer, address(0), validDeposits, 1000e18, 0 payer, address(0), validDeposits, 1000e18, 0
); );
// Test deadline exceeded // Test deadline exceeded
// The default timestamp is 1 and 1-0 is 0 which means "ignore deadline," so we need to set a proper timestamp. // The default timestamp is 1 and 1-0 is 0 which means "ignore deadline," so we need to set a proper timestamp.
int128 kappaDeadline = LMSRStabilized.computeKappaFromSlippage(tokens.length, int128((1 << 64) - 1), int128(1 << 62)); int128 bDeadline = _computeFixedBFromDeposits(tokens.length, bases, validDeposits, int128((1 << 64) - 1), int128(1 << 62));
vm.warp(1000); vm.warp(1000);
vm.expectRevert("Planner: deadline exceeded"); vm.expectRevert("Planner: deadline exceeded");
planner.newPool( planner.newPool(
"Test Pool", "TESTLP", tokens, "Test Pool", "TESTLP", tokens, bases,
kappaDeadline, 3000, 5000, false, bDeadline, 3000, 5000, false,
payer, receiver, validDeposits, 1000e18, block.timestamp - 1 payer, receiver, validDeposits, 1000e18, block.timestamp - 1
); );
} }
@@ -296,12 +324,12 @@ contract PartyPlannerTest is Test {
deposits[0] = INITIAL_DEPOSIT_AMOUNT; deposits[0] = INITIAL_DEPOSIT_AMOUNT;
deposits[1] = INITIAL_DEPOSIT_AMOUNT; deposits[1] = INITIAL_DEPOSIT_AMOUNT;
int128 kappaLoop = LMSRStabilized.computeKappaFromSlippage(tokens.length, int128((1 << 64) - 1), int128(1 << 62)); int128 bLoop = _computeFixedBFromDeposits(tokens.length, bases, deposits, int128((1 << 64) - 1), int128(1 << 62));
(IPartyPool pool,) = planner.newPool( (IPartyPool pool,) = planner.newPool(
string(abi.encodePacked("Pool ", vm.toString(i))), string(abi.encodePacked("Pool ", vm.toString(i))),
string(abi.encodePacked("LP", vm.toString(i))), string(abi.encodePacked("LP", vm.toString(i))),
tokens, tokens, bases,
kappaLoop, 3000, 5000, false, bLoop, 3000, 5000, false,
payer, receiver, deposits, 1000e18, 0 payer, receiver, deposits, 1000e18, 0
); );

View File

@@ -12,7 +12,7 @@ import "../src/PartyPool.sol";
import "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol"; import "../lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol";
import {PartyPlanner} from "../src/PartyPlanner.sol"; import {PartyPlanner} from "../src/PartyPlanner.sol";
import {Deploy} from "./Deploy.sol"; import {Deploy} from "./Deploy.sol";
import {PartyInfo} from "../src/PartyInfo.sol"; import {PartyPoolViewer} from "../src/PartyPoolViewer.sol";
/// @notice Test contract that implements the flash callback for testing flash loans /// @notice Test contract that implements the flash callback for testing flash loans
contract FlashBorrower is IERC3156FlashBorrower { contract FlashBorrower is IERC3156FlashBorrower {
@@ -113,7 +113,7 @@ contract PartyPoolTest is Test {
PartyPlanner planner; PartyPlanner planner;
PartyPool pool; PartyPool pool;
PartyPool pool10; PartyPool pool10;
PartyInfo info; PartyPoolViewer viewer;
address alice; address alice;
address bob; address bob;
@@ -123,6 +123,19 @@ contract PartyPoolTest is Test {
int128 targetSlippage; int128 targetSlippage;
uint256 constant INIT_BAL = 1_000_000; // initial token units for each token (internal==amount when base==1) uint256 constant INIT_BAL = 1_000_000; // initial token units for each token (internal==amount when base==1)
uint256 constant BASE = 1; // use base=1 so internal amounts correspond to raw integers (Q64.64 units)
// Compute fixed b for a pool initialized with numTokens tokens, each deposited with INIT_BAL (BASE == 1).
function _computeFixedB(uint256 numTokens) internal view returns (int128) {
int128 S = ABDKMath64x64.fromUInt(numTokens * INIT_BAL);
int128 one = ABDKMath64x64.fromInt(1);
int128 nMinus1 = ABDKMath64x64.fromUInt(numTokens - 1);
int128 numerator = one.sub(targetSlippage.mul(nMinus1));
int128 denominator = one.add(targetSlippage);
int128 E = numerator.div(denominator);
int128 y = ABDKMath64x64.ln(E).neg().div(tradeFrac);
return S.div(y);
}
function setUp() public { function setUp() public {
planner = Deploy.newPartyPlanner(); planner = Deploy.newPartyPlanner();
@@ -163,11 +176,16 @@ contract PartyPoolTest is Test {
tokens[1] = IERC20(address(token1)); tokens[1] = IERC20(address(token1));
tokens[2] = IERC20(address(token2)); tokens[2] = IERC20(address(token2));
uint256[] memory bases = new uint256[](3);
bases[0] = BASE;
bases[1] = BASE;
bases[2] = BASE;
// Deploy pool with a small fee to test fee-handling paths (use 1000 ppm = 0.1%) // Deploy pool with a small fee to test fee-handling paths (use 1000 ppm = 0.1%)
uint256 feePpm = 1000; uint256 feePpm = 1000;
int128 kappa3 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 b3 = _computeFixedB(tokens.length);
pool = Deploy.newPartyPool(address(this), "LP", "LP", tokens, kappa3, feePpm, feePpm, false); pool = Deploy.newPartyPool(address(this), "LP", "LP", tokens, bases, b3, feePpm, feePpm, false);
// Transfer initial deposit amounts into pool before initial mint (pool expects _tokens already in contract) // Transfer initial deposit amounts into pool before initial mint (pool expects _tokens already in contract)
// We deposit equal amounts INIT_BAL for each token // We deposit equal amounts INIT_BAL for each token
@@ -176,7 +194,7 @@ contract PartyPoolTest is Test {
token2.transfer(address(pool), INIT_BAL); token2.transfer(address(pool), INIT_BAL);
// Perform initial mint (initial deposit); receiver is this contract // Perform initial mint (initial deposit); receiver is this contract
pool.initialMint(address(this), INIT_BAL * tokens.length * 10**18); pool.initialMint(address(this), 0);
// Set up pool10 with 10 _tokens // Set up pool10 with 10 _tokens
IERC20[] memory tokens10 = new IERC20[](10); IERC20[] memory tokens10 = new IERC20[](10);
@@ -191,8 +209,13 @@ contract PartyPoolTest is Test {
tokens10[8] = IERC20(address(token8)); tokens10[8] = IERC20(address(token8));
tokens10[9] = IERC20(address(token9)); tokens10[9] = IERC20(address(token9));
int128 kappa10 = LMSRStabilized.computeKappaFromSlippage(tokens10.length, tradeFrac, targetSlippage); uint256[] memory bases10 = new uint256[](10);
pool10 = Deploy.newPartyPool(address(this), "LP10", "LP10", tokens10, kappa10, feePpm, feePpm, false); for (uint i = 0; i < 10; i++) {
bases10[i] = BASE;
}
int128 b10 = _computeFixedB(tokens10.length);
pool10 = Deploy.newPartyPool(address(this), "LP10", "LP10", tokens10, bases10, b10, feePpm, feePpm, false);
// Mint additional _tokens for pool10 initial deposit // Mint additional _tokens for pool10 initial deposit
token0.mint(address(this), INIT_BAL); token0.mint(address(this), INIT_BAL);
@@ -244,7 +267,7 @@ contract PartyPoolTest is Test {
token8.mint(bob, INIT_BAL); token8.mint(bob, INIT_BAL);
token9.mint(bob, INIT_BAL); token9.mint(bob, INIT_BAL);
info = Deploy.newInfo(); viewer = Deploy.newViewer();
} }
/// @notice Basic sanity: initial mint should have produced LP _tokens for this contract and the pool holds _tokens. /// @notice Basic sanity: initial mint should have produced LP _tokens for this contract and the pool holds _tokens.
@@ -286,7 +309,7 @@ contract PartyPoolTest is Test {
token2.approve(address(pool), type(uint256).max); token2.approve(address(pool), type(uint256).max);
// Inspect the deposit amounts that the pool will require (these are rounded up) // Inspect the deposit amounts that the pool will require (these are rounded up)
uint256[] memory deposits = info.mintAmounts(pool, 1); uint256[] memory deposits = viewer.mintAmounts(pool, 1);
// Basic sanity: deposits array length must match token count and not all zero necessarily // Basic sanity: deposits array length must match token count and not all zero necessarily
assertEq(deposits.length, 3); assertEq(deposits.length, 3);
@@ -328,7 +351,7 @@ contract PartyPoolTest is Test {
uint256 totalLpBefore = pool.totalSupply(); uint256 totalLpBefore = pool.totalSupply();
// Compute required deposits and perform mint for 1 wei // Compute required deposits and perform mint for 1 wei
uint256[] memory deposits = info.mintAmounts(pool, 1); uint256[] memory deposits = viewer.mintAmounts(pool, 1);
// Sum deposits as deposited_value // Sum deposits as deposited_value
uint256 depositedValue = 0; uint256 depositedValue = 0;
@@ -369,7 +392,7 @@ contract PartyPoolTest is Test {
// Request half of LP supply // Request half of LP supply
uint256 want = totalLp / 2; uint256 want = totalLp / 2;
uint256[] memory deposits = info.mintAmounts(pool, want); uint256[] memory deposits = viewer.mintAmounts(pool, want);
// We expect each deposit to be roughly half the pool balance, but due to rounding up it should satisfy: // We expect each deposit to be roughly half the pool balance, but due to rounding up it should satisfy:
// deposits[i] * 2 >= cached balance (i.e., rounding up) // deposits[i] * 2 >= cached balance (i.e., rounding up)
@@ -386,7 +409,7 @@ contract PartyPoolTest is Test {
assertTrue(totalLp > 0, "precondition: LP > 0"); assertTrue(totalLp > 0, "precondition: LP > 0");
// Compute amounts required to redeem entire supply (should be current balances) // Compute amounts required to redeem entire supply (should be current balances)
uint256[] memory withdrawAmounts = info.burnAmounts(pool, totalLp); uint256[] memory withdrawAmounts = viewer.burnAmounts(pool, totalLp);
// Sanity: withdrawAmounts should equal pool balances (or very close due to rounding) // Sanity: withdrawAmounts should equal pool balances (or very close due to rounding)
for (uint i = 0; i < withdrawAmounts.length; i++) { for (uint i = 0; i < withdrawAmounts.length; i++) {
@@ -423,7 +446,7 @@ contract PartyPoolTest is Test {
// Execute swap: token0 -> token1 // Execute swap: token0 -> token1
vm.prank(alice); vm.prank(alice);
(uint256 amountInUsed, uint256 amountOut, uint256 fee) = pool.swap(alice, bytes4(0), bob, 0, 1, maxIn, 0, 0, false); (uint256 amountInUsed, uint256 amountOut, uint256 fee) = pool.swap(alice, bob, 0, 1, maxIn, 0, 0, false);
// Amounts should be positive and not exceed provided max // Amounts should be positive and not exceed provided max
assertTrue(amountInUsed > 0, "expected some input used"); assertTrue(amountInUsed > 0, "expected some input used");
@@ -452,7 +475,7 @@ contract PartyPoolTest is Test {
vm.prank(alice); vm.prank(alice);
vm.expectRevert(bytes("LMSR: limitPrice <= current price")); vm.expectRevert(bytes("LMSR: limitPrice <= current price"));
pool.swap(alice, bytes4(0), alice, 0, 1, 1000, limitPrice, 0, false); pool.swap(alice, alice, 0, 1, 1000, limitPrice, 0, false);
} }
/// @notice swapToLimit should compute input needed to reach a slightly higher price and execute. /// @notice swapToLimit should compute input needed to reach a slightly higher price and execute.
@@ -490,7 +513,7 @@ contract PartyPoolTest is Test {
if (req == 0) req = 1; if (req == 0) req = 1;
// Compute expected deposit amounts via view // Compute expected deposit amounts via view
uint256[] memory expected = info.mintAmounts(pool, req); uint256[] memory expected = viewer.mintAmounts(pool, req);
// Ensure alice has _tokens and approve pool // Ensure alice has _tokens and approve pool
vm.startPrank(alice); vm.startPrank(alice);
@@ -535,7 +558,7 @@ contract PartyPoolTest is Test {
uint256 req = requests[k]; uint256 req = requests[k];
if (req == 0) req = 1; if (req == 0) req = 1;
uint256[] memory expected = info.mintAmounts(pool10, req); uint256[] memory expected = viewer.mintAmounts(pool10, req);
// Approve all _tokens from alice // Approve all _tokens from alice
vm.startPrank(alice); vm.startPrank(alice);
@@ -613,7 +636,7 @@ contract PartyPoolTest is Test {
} }
// Recompute withdraw amounts via view after any top-up // Recompute withdraw amounts via view after any top-up
uint256[] memory expected = info.burnAmounts(pool, req); uint256[] memory expected = viewer.burnAmounts(pool, req);
// If expected withdraws are all zero (rounding edge), skip this iteration // If expected withdraws are all zero (rounding edge), skip this iteration
if (expected[0] == 0 && expected[1] == 0 && expected[2] == 0) { if (expected[0] == 0 && expected[1] == 0 && expected[2] == 0) {
@@ -670,7 +693,7 @@ contract PartyPoolTest is Test {
vm.stopPrank(); vm.stopPrank();
} }
uint256[] memory expected = info.burnAmounts(pool10, req); uint256[] memory expected = viewer.burnAmounts(pool10, req);
// If expected withdraws are all zero (rounding edge), skip this iteration // If expected withdraws are all zero (rounding edge), skip this iteration
bool allZero = true; bool allZero = true;
@@ -721,7 +744,7 @@ contract PartyPoolTest is Test {
uint256 input = 10_000; uint256 input = 10_000;
// Call swapMint as alice, receive LP to alice // Call swapMint as alice, receive LP to alice
(, uint256 minted, ) = pool.swapMint(alice, alice, 0, input, 0); uint256 minted = pool.swapMint(alice, alice, 0, input, 0);
// minted should be > 0 // minted should be > 0
assertTrue(minted > 0, "swapMint should mint LP"); assertTrue(minted > 0, "swapMint should mint LP");
@@ -751,7 +774,7 @@ contract PartyPoolTest is Test {
uint256 aliceBalBefore = token0.balanceOf(alice); uint256 aliceBalBefore = token0.balanceOf(alice);
(, uint256 minted, ) = pool.swapMint(alice, alice, 0, largeInput, 0); uint256 minted = pool.swapMint(alice, alice, 0, largeInput, 0);
// minted should be > 0 // minted should be > 0
assertTrue(minted > 0, "swapMint large input should still mint LP"); assertTrue(minted > 0, "swapMint large input should still mint LP");
@@ -784,7 +807,7 @@ contract PartyPoolTest is Test {
uint256 bobBefore = token0.balanceOf(bob); uint256 bobBefore = token0.balanceOf(bob);
// Call burnSwap where this contract is the payer (it holds initial LP from setUp) // Call burnSwap where this contract is the payer (it holds initial LP from setUp)
(uint256 payout, ) = pool.burnSwap(address(this), bob, lpToBurn, target, 0, false); uint256 payout = pool.burnSwap(address(this), bob, lpToBurn, target, 0, false);
// Payout must be > 0 // Payout must be > 0
assertTrue(payout > 0, "burnSwap should produce a payout"); assertTrue(payout > 0, "burnSwap should produce a payout");
@@ -949,7 +972,7 @@ contract PartyPoolTest is Test {
for (uint256 i = 0; i < testAmounts.length; i++) { for (uint256 i = 0; i < testAmounts.length; i++) {
uint256 amount = testAmounts[i]; uint256 amount = testAmounts[i];
uint256 fee = info.flashFee(pool, address(token0), amount); uint256 fee = viewer.flashFee(pool, address(token0), amount);
// Calculate expected fee // Calculate expected fee
uint256 expectedFee = (amount * pool.flashFeePpm() + 1_000_000 - 1) / 1_000_000; // ceiling uint256 expectedFee = (amount * pool.flashFeePpm() + 1_000_000 - 1) / 1_000_000; // ceiling
@@ -972,15 +995,20 @@ contract PartyPoolTest is Test {
tokens[1] = IERC20(address(token1)); tokens[1] = IERC20(address(token1));
tokens[2] = IERC20(address(token2)); tokens[2] = IERC20(address(token2));
uint256[] memory bases = new uint256[](3);
bases[0] = BASE;
bases[1] = BASE;
bases[2] = BASE;
uint256 feePpm = 1000; uint256 feePpm = 1000;
// Pool with default initialization (lpTokens = 0) // Pool with default initialization (lpTokens = 0)
int128 kappaDefault = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 bDefault = _computeFixedB(tokens.length);
PartyPool poolDefault = Deploy.newPartyPool(address(this), "LP_DEFAULT", "LP_DEFAULT", tokens, kappaDefault, feePpm, feePpm, false); PartyPool poolDefault = Deploy.newPartyPool(address(this), "LP_DEFAULT", "LP_DEFAULT", tokens, bases, bDefault, feePpm, feePpm, false);
// Pool with custom initialization (lpTokens = custom amount) // Pool with custom initialization (lpTokens = custom amount)
int128 kappaCustom = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 bCustom = _computeFixedB(tokens.length);
PartyPool poolCustom = Deploy.newPartyPool(address(this), "LP_CUSTOM", "LP_CUSTOM", tokens, kappaCustom, feePpm, feePpm, false); PartyPool poolCustom = Deploy.newPartyPool(address(this), "LP_CUSTOM", "LP_CUSTOM", tokens, bases, bCustom, feePpm, feePpm, false);
// Mint additional _tokens for both pools // Mint additional _tokens for both pools
token0.mint(address(this), INIT_BAL * 2); token0.mint(address(this), INIT_BAL * 2);
@@ -1024,8 +1052,8 @@ contract PartyPoolTest is Test {
token0.approve(address(poolCustom), type(uint256).max); token0.approve(address(poolCustom), type(uint256).max);
// Perform identical swaps: token0 -> token1 // Perform identical swaps: token0 -> token1
(uint256 amountInDefault, uint256 amountOutDefault, uint256 feeDefault) = poolDefault.swap(alice, bytes4(0), alice, 0, 1, swapAmount, 0, 0, false); (uint256 amountInDefault, uint256 amountOutDefault, uint256 feeDefault) = poolDefault.swap(alice, alice, 0, 1, swapAmount, 0, 0, false);
(uint256 amountInCustom, uint256 amountOutCustom, uint256 feeCustom) = poolCustom.swap(alice, bytes4(0), alice, 0, 1, swapAmount, 0, 0, false); (uint256 amountInCustom, uint256 amountOutCustom, uint256 feeCustom) = poolCustom.swap(alice, alice, 0, 1, swapAmount, 0, 0, false);
// Swap results should be identical // Swap results should be identical
assertEq(amountInDefault, amountInCustom, "Swap input amounts should be identical"); assertEq(amountInDefault, amountInCustom, "Swap input amounts should be identical");
@@ -1044,12 +1072,17 @@ contract PartyPoolTest is Test {
tokens[1] = IERC20(address(token1)); tokens[1] = IERC20(address(token1));
tokens[2] = IERC20(address(token2)); tokens[2] = IERC20(address(token2));
uint256[] memory bases = new uint256[](3);
bases[0] = BASE;
bases[1] = BASE;
bases[2] = BASE;
uint256 feePpm = 1000; uint256 feePpm = 1000;
int128 kappaDefault2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 bDefault2 = _computeFixedB(tokens.length);
PartyPool poolDefault = Deploy.newPartyPool(address(this), "LP_DEFAULT", "LP_DEFAULT", tokens, kappaDefault2, feePpm, feePpm, false); PartyPool poolDefault = Deploy.newPartyPool(address(this), "LP_DEFAULT", "LP_DEFAULT", tokens, bases, bDefault2, feePpm, feePpm, false);
int128 kappaCustom2 = LMSRStabilized.computeKappaFromSlippage(tokens.length, tradeFrac, targetSlippage); int128 bCustom2 = _computeFixedB(tokens.length);
PartyPool poolCustom = Deploy.newPartyPool(address(this), "LP_CUSTOM", "LP_CUSTOM", tokens, kappaCustom2, feePpm, feePpm, false); PartyPool poolCustom = Deploy.newPartyPool(address(this), "LP_CUSTOM", "LP_CUSTOM", tokens, bases, bCustom2, feePpm, feePpm, false);
// Mint additional _tokens // Mint additional _tokens
token0.mint(address(this), INIT_BAL * 4); token0.mint(address(this), INIT_BAL * 4);
@@ -1096,8 +1129,8 @@ contract PartyPoolTest is Test {
token2.approve(address(poolCustom), type(uint256).max); token2.approve(address(poolCustom), type(uint256).max);
// Get required deposit amounts for both pools // Get required deposit amounts for both pools
uint256[] memory depositsDefault = info.mintAmounts(poolDefault, lpRequestDefault); uint256[] memory depositsDefault = viewer.mintAmounts(poolDefault, lpRequestDefault);
uint256[] memory depositsCustom = info.mintAmounts(poolCustom, lpRequestCustom); uint256[] memory depositsCustom = viewer.mintAmounts(poolCustom, lpRequestCustom);
// Deposits should be identical (same proportion of identical balances) // Deposits should be identical (same proportion of identical balances)
assertEq(depositsDefault[0], depositsCustom[0], "Token0 deposits should be identical"); assertEq(depositsDefault[0], depositsCustom[0], "Token0 deposits should be identical");
@@ -1124,52 +1157,5 @@ contract PartyPoolTest is Test {
vm.stopPrank(); vm.stopPrank();
} }
/// @notice Verify that the initial relative price between token0 and token1 is 1.0000000
function testInitialPriceIsOne() public view {
// Query the info viewer for the relative price between token index 0 and 1
int128 price = info.price(pool, 0, 1);
// Expected price is 1.0 in ABDK 64.64 fixed point
int128 expected = ABDKMath64x64.fromInt(1);
// Cast int128 to uint128 then to uint256 for assertEq (values are non-negative)
assertEq(uint256(uint128(price)), uint256(uint128(expected)), "Initial relative price must be 1.0000000");
}
/// @notice Verify that the initial LP price in terms of token0 is 1.0000000
function testInitialPoolPriceIsOne() public {
// Query the info viewer for the pool price for token0
int128 price = info.poolPrice(pool, 0);
// Expected price is 1.0 in ABDK 64.64 fixed point
int128 expected = ABDKMath64x64.fromInt(1);
// Cast int128 to uint128 then to uint256 for assertEq (values are non-negative)
assertEq(uint256(uint128(price)), uint256(uint128(expected)), "Initial pool price must be 1.0000000");
// Mint a small amount of LP into the pool from alice and verify price remains 1.0
vm.startPrank(alice);
// Approve tokens for pool to pull
token0.approve(address(pool), type(uint256).max);
token1.approve(address(pool), type(uint256).max);
token2.approve(address(pool), type(uint256).max);
// Choose a small LP request (1% of supply or at least 1)
uint256 lpRequest = pool.totalSupply() / 100;
if (lpRequest == 0) lpRequest = 1;
// Compute required deposits and perform mint if not trivial
uint256[] memory deposits = info.mintAmounts(pool, lpRequest);
bool allZero = true;
for (uint i = 0; i < deposits.length; i++) { if (deposits[i] != 0) { allZero = false; break; } }
if (!allZero) {
pool.mint(alice, alice, lpRequest, 0);
}
vm.stopPrank();
// Re-query the pool price and ensure it remains 1.0 (within exact fixed-point equality)
int128 priceAfter = info.poolPrice(pool, 0);
assertEq(uint256(uint128(priceAfter)), uint256(uint128(expected)), "Pool price should remain 1.0000000 after mint");
}
} }
/* solhint-enable */ /* solhint-enable */