├── .circleci └── config.yml ├── .github ├── isssue_template.md └── pull_request_template.md ├── .gitignore ├── .gitmodules ├── .npmignore ├── .solhint.json ├── .solhintignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── README.md ├── deployments └── mainnet.json ├── foundry.toml ├── local_devnet ├── docker-compose.fork.yml └── export_addresses.sh ├── package.json ├── py └── esm-fixer.py ├── specs ├── aztec │ ├── dataprovider │ │ └── readme.md │ └── subsidy │ │ └── readme.md └── bridges │ ├── TEMPLATE.md │ ├── angle │ └── readme.md │ ├── curve │ ├── exchangeBridge │ │ ├── CurveStethBridge.svg │ │ └── readme.md │ └── lpbridge │ │ ├── CurveLp.svg │ │ └── readme.md │ ├── dca │ └── readme.md │ ├── donation │ └── readme.md │ ├── erc4626 │ └── readme.md │ ├── lido │ ├── LidoBridge.svg │ └── readme.md │ ├── liquity │ └── TroveBridge │ │ └── readme.md │ ├── uniswap │ └── readme.md │ └── yearn │ └── readme.md ├── src ├── aztec │ ├── DataProvider.sol │ ├── Subsidy.sol │ └── interfaces │ │ ├── IDefiBridge.sol │ │ └── ISubsidy.sol ├── bridges │ ├── angle │ │ └── AngleSLPBridge.sol │ ├── base │ │ ├── BridgeBase.sol │ │ └── ErrorLib.sol │ ├── curve │ │ ├── CurveStEthBridge.sol │ │ ├── CurveStEthLpBridge.vy │ │ └── Deployer.sol │ ├── dca │ │ ├── BiDCABridge.sol │ │ ├── SafeCastLib.sol │ │ └── UniswapDCABridge.sol │ ├── donation │ │ └── DonationBridge.sol │ ├── element │ │ ├── ElementBridge.sol │ │ └── MinHeap.sol │ ├── erc4626 │ │ └── ERC4626Bridge.sol │ ├── example │ │ └── ExampleBridge.sol │ ├── lido │ │ └── LidoBridge.sol │ ├── liquity │ │ ├── StabilityPoolBridge.sol │ │ ├── StakingBridge.sol │ │ └── TroveBridge.sol │ ├── uniswap │ │ └── UniswapBridge.sol │ └── yearn │ │ └── YearnBridge.sol ├── deployment │ ├── AggregateDeployment.s.sol │ ├── angle │ │ └── AngleSLPDeployment.s.sol │ ├── base │ │ └── BaseDeployment.s.sol │ ├── curve │ │ ├── CurveDeployment.s.sol │ │ └── CurveStethLpDeployment.s.sol │ ├── dataprovider │ │ └── DataProviderDeployment.s.sol │ ├── dca │ │ └── DCADeployment.s.sol │ ├── donation │ │ └── DonationDeployment.s.sol │ ├── element │ │ └── ElementDeployment.s.sol │ ├── erc4626 │ │ ├── ERC4626Deployment.s.sol │ │ ├── ERC4626DustSetter.s.sol │ │ └── ERC4626Lister.s.sol │ ├── example │ │ └── ExampleDeployment.s.sol │ ├── liquity │ │ └── LiquityTroveDeployment.s.sol │ ├── subsidy │ │ └── SubsidyDeployment.sol │ ├── uniswap │ │ └── UniswapDeployment.s.sol │ └── yearn │ │ └── YearnDeployment.s.sol ├── gas │ ├── angle │ │ └── AngleSLPGas.s.sol │ ├── base │ │ └── GasBase.sol │ ├── curve │ │ ├── CurveGas.s.sol │ │ └── CurveLpGas.s.sol │ ├── dca │ │ └── DCAGas.s.sol │ ├── erc4626 │ │ └── ERC4626Gas.s.sol │ ├── liquity │ │ └── TroveBridgeGas.s.sol │ ├── uniswap │ │ └── UniswapGas.s.sol │ └── yearn │ │ └── YearnGas.s.sol ├── interfaces │ ├── IWETH.sol │ ├── angle │ │ ├── IPoolManager.sol │ │ └── IStableMaster.sol │ ├── chainlink │ │ └── IChainlinkOracle.sol │ ├── compound │ │ ├── ICERC20.sol │ │ └── ICompoundERC4626.sol │ ├── curve │ │ └── ICurvePool.sol │ ├── element │ │ ├── IDeploymentValidator.sol │ │ ├── IPool.sol │ │ ├── ITranche.sol │ │ ├── IVault.sol │ │ └── IWrappedPosition.sol │ ├── lido │ │ ├── ILido.sol │ │ ├── ILidoOracle.sol │ │ └── IWstETH.sol │ ├── liquity │ │ ├── IBorrowerOperations.sol │ │ ├── IHintHelpers.sol │ │ ├── ILQTYStaking.sol │ │ ├── ILiquityBase.sol │ │ ├── IPriceFeed.sol │ │ ├── ISortedTroves.sol │ │ ├── IStabilityPool.sol │ │ └── ITroveManager.sol │ ├── set │ │ ├── IController.sol │ │ ├── IExchangeIssuance.sol │ │ └── ISetToken.sol │ ├── uniswapv3 │ │ ├── IQuoter.sol │ │ ├── ISwapRouter.sol │ │ ├── callback │ │ │ └── IUniswapV3SwapCallback.sol │ │ └── pool │ │ │ ├── IUniswapV3PoolActions.sol │ │ │ ├── IUniswapV3PoolDerivedState.sol │ │ │ └── IUniswapV3PoolImmutables.sol │ └── yearn │ │ ├── IYearnRegistry.sol │ │ └── IYearnVault.sol ├── libraries │ ├── aave │ │ ├── DataTypes.sol │ │ └── WadRayMath.sol │ └── uniswapv3 │ │ ├── FullMath.sol │ │ └── TickMath.sol ├── scripts │ ├── FinalisationScript.sol │ └── SubsidyLogger.sol └── test │ ├── aztec │ ├── base │ │ └── BridgeTestBase.sol │ ├── dataprovider │ │ └── DataProvider.t.sol │ └── subsidy │ │ └── Subsidy.t.sol │ └── bridges │ ├── angle │ ├── AngleSLPE2E.t.sol │ └── AngleSLPUnit.t.sol │ ├── curve │ ├── CurveStEthBridge.t.sol │ ├── CurveStEthLPUnit.t.sol │ └── CurveStEthLpE2E.t.sol │ ├── dca │ ├── BiDCABridge.t.sol │ ├── BiDCABridgeArber.t.sol │ └── BiDCABridgeE2E.t.sol │ ├── donation │ └── DonateBridgeE2E.t.sol │ ├── element │ ├── Element.t.sol │ ├── Heap.t.sol │ ├── HeapTestContract.sol │ ├── MockDeploymentValidator.sol │ └── aztecmocks │ │ ├── DefiBridgeProxy.sol │ │ ├── RollupProcessor.sol │ │ └── libraries │ │ └── TokenTransfers.sol │ ├── erc4626 │ ├── ERC4626.t.sol │ └── mocks │ │ └── WETHVault.sol │ ├── example │ ├── ExampleE2E.t.sol │ └── ExampleUnit.t.sol │ ├── lido │ └── Lido.t.sol │ ├── liquity │ ├── StabilityPoolBridgeE2E.t.sol │ ├── StabilityPoolBridgeInternal.t.sol │ ├── StabilityPoolBridgeUnit.t.sol │ ├── StakingBridgeE2E.t.sol │ ├── StakingBridgeInternal.t.sol │ ├── StakingBridgeUnit.t.sol │ ├── TroveBridgeE2E.t.sol │ ├── TroveBridgeTestBase.sol │ ├── TroveBridgeUnit.t.sol │ └── utils │ │ ├── MockPriceFeed.sol │ │ └── TestUtil.sol │ ├── uniswap │ ├── UniswapBridgeE2E.t.sol │ ├── UniswapBridgeInternal.t.sol │ └── UniswapBridgeUnit.t.sol │ └── yearn │ ├── YearnBridgeE2E.t.sol │ ├── YearnBridgeE2EApproval.t.sol │ └── YearnUnit.t.sol ├── tsconfig.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: "2.1" 2 | orbs: 3 | node: circleci/node@5.0.0 4 | jobs: 5 | build-and-test: 6 | docker: 7 | - image: "cimg/python:3.10.6" 8 | steps: 9 | - checkout 10 | - node/install: 11 | install-yarn: true 12 | node-version: "16.13" 13 | - run: 14 | name: Setup Vyper 15 | shell: /bin/bash 16 | command: | 17 | pip install vyper 18 | export PATH=/home/cicleci/.local/bin:$PATH 19 | vyper --version 20 | - run: 21 | name: Setup Foundry 22 | shell: /bin/bash 23 | command: | 24 | yarn config set script-shell /bin/bash 25 | yarn install:foundryup 26 | export PATH=/home/circleci/.foundry/bin:$PATH 27 | yarn install:foundry 28 | - run: 29 | name: Build Project 30 | shell: /bin/bash 31 | command: | 32 | export PATH=/home/circleci/.foundry/bin:$PATH 33 | yarn install:dependencies 34 | yarn build 35 | - run: 36 | name: Check Formatting 37 | shell: /bin/bash 38 | command: | 39 | yarn config set script-shell /bin/bash 40 | export PATH=/home/circleci/.foundry/bin:$PATH 41 | yarn formatting:check 42 | - run: 43 | name: Check Linting Errors in Contracts 44 | shell: /bin/bash 45 | command: | 46 | yarn config set script-shell /bin/bash 47 | yarn lint 48 | - run: 49 | name: Test Contracts 50 | shell: /bin/bash 51 | command: | 52 | yarn config set script-shell /bin/bash 53 | export PATH=/home/circleci/.foundry/bin:$PATH 54 | yarn test 55 | publish: 56 | docker: 57 | - image: "cimg/python:3.10.6" 58 | steps: 59 | - checkout 60 | - node/install: 61 | install-yarn: true 62 | node-version: "16.13" 63 | - run: 64 | name: Authenticate with registry 65 | command: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc 66 | - run: 67 | name: Publish 68 | shell: /bin/bash 69 | command: | 70 | yarn publish --access public 71 | 72 | workflows: 73 | install: 74 | jobs: 75 | - build-and-test 76 | deploy: 77 | jobs: 78 | - publish: 79 | filters: 80 | tags: 81 | only: /^v.*/ 82 | branches: 83 | ignore: /.*/ 84 | -------------------------------------------------------------------------------- /.github/isssue_template.md: -------------------------------------------------------------------------------- 1 | ## Expected Behavior 2 | 3 | ## Actual Behavior 4 | 5 | ## Steps to Reproduce the Problem 6 | 7 | 1. 8 | 2. 9 | 3. 10 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please provide a paragraph or two giving a summary of the change, including relevant motivation and context. 4 | 5 | # Checklist: 6 | 7 | - [ ] I have reviewed my diff in github, line by line. 8 | - [ ] Every change is related to the PR description. 9 | - [ ] There are no unexpected formatting changes, or superfluous debug logs. 10 | - [ ] The branch has been rebased against the head of its merge target. 11 | - [ ] I'm happy for the PR to be merged at the reviewers next convenience. 12 | - [ ] NatSpec documentation of all the non-test functions is present and is complete. 13 | - [ ] Continuous integration (CI) passes. 14 | - [ ] Command `forge coverage --match-contract MyContract` returns 100% line coverage. 15 | - [ ] All the possible reverts are tested. 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | node_modules/ 4 | yarn-error.log 5 | typechain-types/ 6 | broadcast/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/rollup-encoder"] 5 | path = lib/rollup-encoder 6 | url = https://github.com/AztecProtocol/rollup-encoder 7 | [submodule "lib/openzeppelin-contracts"] 8 | path = lib/openzeppelin-contracts 9 | url = https://github.com/openzeppelin/openzeppelin-contracts 10 | branch = v4.8.0 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | cache/ 2 | out/ 3 | lib/ 4 | src/ 5 | node_modules/ 6 | typechain-types/ 7 | yarn.lock 8 | foundry.toml -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "compiler-version": ["error", ">=0.8.4"], 5 | "func-visibility": ["error", { "ignoreConstructors": true }], 6 | "no-empty-blocks": "off", 7 | "no-unused-vars": ["error"], 8 | "state-visibility": ["error"], 9 | "not-rely-on-time": "off", 10 | "const-name-snakecase": ["error", { "treatImmutableVarAsConstant": true }], 11 | "var-name-mixedcase": ["error", { "treatImmutableVarAsConstant": true }], 12 | "error-name-mixedcase": ["error"], 13 | "private-func-leading-underscore": ["error"], 14 | "private-vars-no-leading-underscore": ["error"], 15 | "func-param-name-leading-underscore": ["error"], 16 | "func-param-name-mixedcase": ["error"], 17 | "custom-error-over-require": ["error"], 18 | "strict-override": ["error"], 19 | "strict-import": ["error"], 20 | "ordering": ["error"] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | src/interfaces/ 2 | src/libraries/ 3 | src/test/bridges/element/MockDeploymentValidator.sol 4 | # TODO: remove the following 2 lines once the bridge is deprecated 5 | src/bridges/element/ 6 | src/test/bridges/element/aztecmocks -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][mozilla coc]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][faq]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [mozilla coc]: https://github.com/mozilla/diversity 131 | [faq]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We are looking for community members with experience writing Solidity contracts to write bridge contracts. As Aztec integrates with more Ethereum protocols, more transactions will flow through the network making it faster, cheaper and more private for everyone. 4 | 5 | We have a grants program where you can get funding to write a custom bridge. You can find more information about the program [here](https://www.notion.so/aztecnetwork/Aztec-Grants-19896948e74b4024a458cdeddbe9574f). 6 | 7 | In the near future, adding a custom bridge to the Aztec network will be permissionless. Currently bridges must be added to the Aztec Rollup processor contract manually by the team. This is a temporary measure as we bootstrap the network. 8 | 9 | This repo has been built with Foundry. Given the inter-connected nature of Aztec Connect Bridges with existing mainnet protocols, we decided Foundry / forge offered the best support for testing. This repo should make debugging, mainnet-forking, impersonation and gas profiling simple. It makes sense to test Solidity contracts with Solidty not with the added complication of Ethers / Typescript. 10 | 11 | For more information, refer to the [README](./README.md). 12 | 13 | Please reach out on Discord with any questions. You can join our Discord [here](https://discord.gg/ctGpCgkBFt). 14 | -------------------------------------------------------------------------------- /deployments/mainnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "ElementBridge": "0xaeD181779A8AAbD8Ce996949853FEA442C2CDB47", 3 | "CurveStEthBridge": "0xe09801dA4C74e62fB42DFC8303a1C1BD68073D1a", 4 | "Subsidy": "0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA", 5 | "YearnBridge": "0xE71A50a78CcCff7e20D8349EED295F12f0C8C9eF", 6 | "ERC4626Bridge": "0x3578D6D5e1B4F07A48bb1c958CBfEc135bef7d98", 7 | "DataProvider": "0xB4319947947781FFe91dDf96A32aF2D4693FEf64", 8 | "UniswapDCABridge": "0x94679A39679ffE53B53b6a1187aa1c649A101321", 9 | "UniswapBridge": "0x5594808e8A7b44da9D2382E6d72ad50a3e2571E0", 10 | "TroveBridge-275": "0x998650bf01A6424F9B11debd85a29090906cB559", 11 | "TroveBridge-400": "0x646Df2Dc98741a0Ab5798DeAC6Fc62411dA41D96" 12 | } 13 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | remappings = ['@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/', 'forge-std/=lib/forge-std/src', 'rollup-encoder/=lib/rollup-encoder/src'] 6 | fuzz_runs = 256 7 | gas_reports = ["*"] 8 | eth-rpc-url = 'https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c' 9 | solc_version = '0.8.10' 10 | ffi = true 11 | optimizer = true 12 | optimizer_runs = 100000 13 | 14 | # See more config options https://github.com/gakonst/foundry/tree/master/config 15 | -------------------------------------------------------------------------------- /local_devnet/docker-compose.fork.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | fork: 4 | image: ghcr.io/foundry-rs/foundry:nightly-8c4294c1d2321e20a3543fbd9a813d47053a8303 5 | entrypoint: "anvil -p=8545 --host 0.0.0.0 --fork-url ${FORK_URL} --chain-id ${CHAIN_ID} --silent" 6 | ports: 7 | - "8545:8545" 8 | 9 | contracts: 10 | platform: linux/amd64 11 | image: aztecprotocol/contracts:latest 12 | environment: 13 | ETHEREUM_HOST: http://fork:8545 14 | PORT: 8547 15 | network: "DONT_CARE" 16 | command: ./scripts/start_e2e.sh 17 | ports: 18 | - "8547:8547" 19 | depends_on: 20 | - fork 21 | 22 | falafel: 23 | platform: linux/amd64 24 | image: aztecprotocol/falafel:latest 25 | environment: 26 | ETHEREUM_HOST: http://fork:8545 27 | CONTRACTS_HOST: http://contracts:8547 28 | NUM_INNER_ROLLUP_TXS: ${NUM_INNER_ROLLUP_TXS:-3} 29 | NUM_OUTER_ROLLUP_PROOFS: ${NUM_OUTER_ROLLUP_PROOFS:-1} 30 | PROVERLESS: "true" 31 | MAX_CIRCUIT_SIZE: 8192 32 | PROOF_GENERATOR_MODE: local 33 | NO_BUILD: "true" 34 | PORT: 8081 35 | INITIAL_RUNTIME_CONFIG_PATH: "./config/dev_testnet_initial_config.json" 36 | depends_on: 37 | - contracts 38 | command: start:e2e 39 | ports: 40 | - "8081:8081" 41 | -------------------------------------------------------------------------------- /local_devnet/export_addresses.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Output the lister and deployer addresses 4 | # The anvil deployer address for the mainnet fork 5 | LISTER_ADDRESS="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" 6 | 7 | # Output deployed artifacts addresses (requested fro the contracts container running @ CONTRACTS_HOST) 8 | ADDRESSES=( 9 | ROLLUP_CONTRACT_ADDRESS 10 | FAUCET_CONTRACT_ADDRESS 11 | PERMIT_HELPER_CONTRACT_ADDRESS 12 | FEE_DISTRIBUTOR_ADDRESS 13 | BRIDGE_DATA_PROVIDER_CONTRACT_ADDRESS 14 | ) 15 | 16 | # Wait for host 17 | CONTRACTS_HOST=${CONTRACTS_HOST:-"http://localhost:8547"} 18 | echo "Waiting for contracts host at $CONTRACTS_HOST..." 19 | while ! curl -s $CONTRACTS_HOST > /dev/null; do sleep 1; done; 20 | 21 | # Export keys to env variables 22 | for ADDRESS in $ADDRESSES; do 23 | VALUE=$(curl -s $CONTRACTS_HOST | jq -r .$ADDRESS) 24 | echo "$ADDRESS=$VALUE" 25 | export $ADDRESS=$VALUE 26 | done 27 | export ROLLUP_PROCESSOR_ADDRESS=$ROLLUP_CONTRACT_ADDRESS -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@aztec/bridge-clients", 3 | "version": "0.1.74", 4 | "description": "This repo contains the solidity files for Aztec Connect Bridge Contracts", 5 | "repository": "git@github.com:AztecProtocol/aztec-connect-bridges.git", 6 | "license": "Apache-2.0", 7 | "type": "module", 8 | "scripts": { 9 | "install:foundryup": "curl -L https://foundry.paradigm.xyz | bash", 10 | "install:foundry": "foundryup", 11 | "install:dependencies": "git submodule update --init --recursive && yarn", 12 | "setup": "yarn install:foundryup && yarn install:foundry && yarn install:dependencies", 13 | "clean": "rm -rf ./cache ./dest ./out ./typechain-types", 14 | "build": "forge build", 15 | "compile:typechain": "yarn clean && forge build --skip test --skip script && typechain --target ethers-v5 --out-dir ./typechain-types './out/?(DataProvider|RollupProcessor|*Bridge|I*).sol/*.json'", 16 | "test:pinned:14000000": "forge test --fork-block-number 14000000 --match-contract 'Element' --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c", 17 | "test:pinned:14950000": "forge test --fork-block-number 14950000 --match-contract 'BiDCA' --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c", 18 | "test:pinned:14970000": "forge test --fork-block-number 14970000 -m 'testRedistributionSuccessfulSwap|testRedistributionExitWhenICREqualsMCR' --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c", 19 | "test:pinned:14972000": "forge test --fork-block-number 14972000 -m 'testRedistributionFailingSwap' --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c", 20 | "test:pinned:16000000": "forge test --fork-block-number 16000000 --match-contract 'Yearn' --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c", 21 | "test:pinned": "yarn test:pinned:14000000 && yarn test:pinned:16000000 && yarn test:pinned:14950000 && yarn test:pinned:14970000 && yarn test:pinned:14972000", 22 | "test": "forge test --fork-block-number 16000000 --no-match-contract 'Element|BiDCA|Yearn' --no-match-test 'testRedistribution' --fork-url https://mainnet.infura.io/v3/9928b52099854248b3a096be07a6b23c && yarn test:pinned", 23 | "formatting": "forge fmt", 24 | "formatting:check": "forge fmt --check", 25 | "lint": "solhint --config ./.solhint.json --fix \"src/**/*.sol\"" 26 | }, 27 | "devDependencies": { 28 | "solhint": "https://github.com/LHerskind/solhint", 29 | "typechain": "^8.1.1", 30 | "typescript": "^4.9.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /py/esm-fixer.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pathlib import Path 3 | 4 | for path in Path('../typechain-types/').rglob('**/*'): 5 | 6 | if Path.is_file(path): 7 | with open(path, 'r') as file: 8 | data = file.read() 9 | 10 | # Fix the ones where we need index.js 11 | outer_pattern = '\* as \w* from \".*\";' 12 | to_fix = re.findall(outer_pattern, data) 13 | y = re.split(outer_pattern, data) 14 | 15 | replacements = [] 16 | for x in to_fix: 17 | inner_pattern = "\* as \w* from \"(.*)\";" 18 | _x = re.search(inner_pattern, x) 19 | cleaned = "{0}/index.js".format(_x[1]) 20 | rep = _x[0].replace(_x[1], cleaned) 21 | replacements.append(rep) 22 | 23 | full = [] 24 | for i in range(len(y)): 25 | full.append(y[i]) 26 | if i < len(replacements): 27 | full.append(replacements[i]) 28 | 29 | data = "".join(full) 30 | 31 | # The more direct .js ones 32 | outer_pattern = '\} from \"[.]{1,2}.*\";' 33 | to_fix = re.findall(outer_pattern, data) 34 | y = re.split(outer_pattern, data) 35 | 36 | replacements = [] 37 | for x in to_fix: 38 | inner_pattern = "\} from \"[.]{1,2}(.*)\";" 39 | _x = re.search(inner_pattern, x) 40 | cleaned = "{0}.js".format(_x[1]) 41 | rep = _x[0].replace(_x[1], cleaned) 42 | replacements.append(rep) 43 | 44 | full = [] 45 | for i in range(len(y)): 46 | full.append(y[i]) 47 | if i < len(replacements): 48 | full.append(replacements[i]) 49 | 50 | data = "".join(full) 51 | 52 | with open(path, 'w+') as f: 53 | f.write(data) -------------------------------------------------------------------------------- /specs/aztec/dataprovider/readme.md: -------------------------------------------------------------------------------- 1 | # DataProvider 2 | 3 | ## What does it do? 4 | 5 | It is a contract we use as a source of truth when it comes to configuration of bridges and assets. 6 | It is mainly used by our frontend to get a bridge or asset information by a tag, but the information can be used by anyone. 7 | 8 | ## Usage 9 | 10 | The contract is deployed [here](https://etherscan.io/address/0xB4319947947781FFe91dDf96A32aF2D4693FEf64) and these are the 4 relevant functions: 11 | 12 | ```solidity 13 | function getAsset(uint256 _assetId) public view returns (AssetData memory); 14 | 15 | function getAsset(string memory _tag) public view returns (AssetData memory); 16 | 17 | function getAssets() public view returns (AssetData[] memory); 18 | 19 | function getBridges() public view returns (BridgeData[] memory); 20 | ``` 21 | 22 | The easiest way to access it, if already using this repository is to execute the `readProvider(address _provider)` script in the DataProviderDeployment solidity file. To get the address of the data provider, you can query the falafel status endpoint `https://api.aztec.network//falafel/status` with `DEPLOY_TAG=`. 23 | 24 | ```bash 25 | export NETWORK= && export SIMULATE_ADMIN=false 26 | export ETH_RPC_URL= 27 | forge script DataProviderDeployment --rpc-url $ETH_RPC_URL --sig "readProvider(address)" DATA_PROVIDER_ADDRESS 28 | ``` 29 | 30 | ## Usage by owner 31 | 32 | Updating values stored in the data provider is only possible by the owner of the contract. 33 | 34 | Before running the commands bellow export relevant environment variables: 35 | 36 | ```bash 37 | export RPC="https://mainnet.infura.io/v3/737bcb5393b146d7870be2f68a7cea9c" && PRIV_KEY="PROVIDER_OWNER_PRIVATE_KEY" 38 | ``` 39 | 40 | ### Adding a bridge 41 | 42 | ```bash 43 | cast send 0xB4319947947781FFe91dDf96A32aF2D4693FEf64 "addBridge(uint256,string)" "2" "ExampleBridge" --rpc-url $RPC --private-key $PRIV_KEY 44 | ``` 45 | 46 | ### Adding an asset 47 | 48 | ```bash 49 | cast send 0xB4319947947781FFe91dDf96A32aF2D4693FEf64 "addAsset(uint256,string)" "2" "wsteth" --rpc-url $RPC --private-key $PRIV_KEY 50 | ``` 51 | 52 | ### Adding multiple assets and bridges 53 | 54 | ```bash 55 | cast send 0xB4319947947781FFe91dDf96A32aF2D4693FEf64 "addAssetsAndBridges(uint256[],string[],uint256[],string[])" '[2,1]' '["wsteth","dai"]' '[5,8]' '["ExampleBridge_deposit","ExampleBridge_withdraw"]' --rpc-url $RPC --private-key $PRIV_KEY 56 | ``` 57 | -------------------------------------------------------------------------------- /specs/bridges/TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Aztec Connect Bridges Specification Template 2 | 3 | _Help the Aztec community make Aztec Connect easier to build on and interact with by documenting your work. 4 | This spec template is meant to help you provide all of the information that a developer needs to work with your bridge. 5 | Complete specifications will be linked in the official Aztec docs at https://docs.aztec.network._ 6 | 7 | You can view an example spec [here](#add-link). 8 | 9 | 1. What does this bridge do? Why did you build it? 10 | 2. What protocol(s) does the bridge interact with? 11 | 12 | - Include links to website, github, etherscan, etc 13 | - Include a small description of the protocol(s) 14 | 15 | 3. What is the flow of the bridge? 16 | 17 | - What actions does this bridge make possible? 18 | - Are all bridge interactions synchronous, or is the a asynchronous flow? 19 | - For each interaction define: 20 | - All input tokens, including [AztecType](https://github.com/AztecProtocol/aztec-connect-bridges/blob/master/src/aztec/libraries/AztecTypes.sol) info 21 | - All output tokens, including [AztecType](https://github.com/AztecProtocol/aztec-connect-bridges/blob/master/src/aztec/libraries/AztecTypes.sol) info 22 | - All relevant bridge address ids (may fill in after deployment) 23 | - use of auxData 24 | - gas usage 25 | - cases that that would make the interaction revert (low liquidity etc) 26 | - Please include any diagrams that would be helpful to understand asset flow. 27 | 28 | 4. Please list any edge cases that may restrict the usefulness of the bridge or that the bridge prevents explicit. 29 | 30 | 5. How can the accounting of the bridge be impacted by interactions performed by other parties than the bridge? Example, if borrowing, how does it handle liquidations etc. 31 | 32 | 6. Is this contract upgradable? If so, what are the restrictions on upgradability? 33 | 34 | 7. Does this bridge maintain state? If so, what is stored and why? 35 | 36 | 8. Any other relevant information 37 | -------------------------------------------------------------------------------- /specs/bridges/angle/readme.md: -------------------------------------------------------------------------------- 1 | # Aztec Connect Bridges Specification Template 2 | 3 | ## What does this bridge do? Why did you build it? 4 | 5 | The bridge allows a user to deposit ERC20 tokens to Angle Protocol and receive in exchange sanTokens (yield bearing tokens). 6 | It is build to allow users to earn yield on their tokens. 7 | 8 | ## What protocol(s) does the bridge interact with? 9 | 10 | The bridge interacts with [Angle Protocol](https://angle.money/). 11 | Angle is the first decentralized, capital efficient and over-collateralized stablecoin protocol. 12 | [Angle's Github](https://github.com/AngleProtocol/) 13 | 14 | ## What is the flow of the bridge? 15 | 16 | There are 2 flows: 17 | 18 | - deposit ERC20 and receive sanTokens (yield bearing) 19 | - withdraw ERC20 (by sending back your sanTokens) 20 | 21 | Input tokens currently accepted by Angle are: DAI, USDC, wETH and FRAX. 22 | 23 | sanTokens being yield bearing tokens, the amount to be redeemed ultimately could be either higher or lower than what was deposited. 2 cases: 24 | 25 | - interests were positive and accrued in the protocol -> being redistributed to SLP -> withdraw more ERC20 than deposited 26 | - losses happened in the protocol -> SLPs are impacted -> withdraw less than what was deposited 27 | In no case will withdrawals revert. You will always be able to withdraw some of the underlying ERC20. 28 | 29 | ## What functions are available in [/src/client](./client)? 30 | 31 | Main functions are `getAuxData` and `getExpectedOutput`. 32 | `getAuxData` returns the correct `auxData` to be passed to the bridge contract based on input and output assets. 33 | `getExpectedOutput` returns the expected amount of ERC20 returns from a deposit or a withdraw to Angle Protocol. 34 | 35 | ## Is this contract upgradable? If so, what are the restrictions on upgradability? 36 | 37 | No, bridge is immutable. 38 | Some of the contracts in the Angle Protocol are upgradable. Controlled by a 4 out of 6 multisig. 39 | You can find more information here: https://developers.angle.money/governance-and-cross-module-contracts/common-modules#smart-contracts-upgradeability 40 | and here: https://docs.angle.money/governance/angle-dao#governance-multi-sig-signers 41 | 42 | ## Does this bridge maintain state? If so, what is stored and why? 43 | 44 | No state needed. 45 | -------------------------------------------------------------------------------- /specs/bridges/curve/exchangeBridge/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Curve stEth Bridge 2 | 3 | ## What does the bridge do? Why build it? 4 | 5 | The bridge swaps `eth` to `stEth` using curve to get a staked eth derivative that earns a yield from staking rewards at the beaconchain. We build it to allow users to earn yield on their eth. 6 | 7 | ## What protocol(s) does the bridge interact with ? 8 | 9 | The bridge interacts with two protocols, namely Lido and Curve. 10 | 11 | [Lido](https://lido.fi/) is a project that build liquid staking derivatives. They allow users to deposit stakeable assets (Eth, Sol etc) and in return get a representation of the staked asset which will grow with staking rewards. We will only be working with `stEth` (staked ether), so we will be using that for explanations going on. 12 | 13 | `stEth` is a rebasing ERC20 token, and a users balance of it will grow/shrink based on accrued staking rewards or slashing events. After the Merge and the hardfork making it possible to withdraw staked ether from the beacon chain, `stEth` can be burned to redeem an equal amount of `eth`. Until then, `stEth` cannot be redeemed at lido directly, but can instead be traded at a secondary market, such as [curve.fi](https://curve.fi/steth). 14 | 15 | [Curve](https://curve.fi/) is a AMM that specializes in pools with low internal volatility (stableswap). It is at the time of writing, the most liquid market for trading between `stEth` and `eth`. 16 | 17 | ## What is the flow of the bridge? 18 | 19 | There are two flows of Curve stEth Bridge, namely deposits and withdraws. 20 | 21 | ![Lido flows](CurveStethBridge.svg) 22 | 23 | ### Deposit 24 | 25 | If the bridge receives `eth` as the input token it will swap it on Curve to get `stEth` (NOTICE: a minimum steth/eth price is passed in the auxdata), and wrap it to `wstEth` before return the tuple `(wstEthAmount, 0, false)` and the rollup pulls the `wstEth` tokens. 26 | 27 | The gas cost E2E for a deposit is ~250K, this is including the transfers to/from the Rollup Processor. 28 | 29 | **Edge cases**: 30 | 31 | - Liquidity might leave, making it impractical to perform swaps at a good rate 32 | 33 | ### Withdrawal 34 | 35 | If the bridge receives `wstEth` as the input token, it will unwrap them to `stEth` before going to curve, where it will swap it (NOTICE: a minimum eth/wsteth is passed in the auxdata). 36 | It will then transfer the eth received to the `ROLLUP_PROCESSOR` for the given `interactionNonce`. 37 | 38 | The gas cost E2E for a withdraw is ~250K, this is including the transfers to/from the Rollup Processor. 39 | 40 | **Edge cases** 41 | 42 | - Liquidity might leave, making it impractical to perform swaps at a good rate 43 | - If the balance of the bridge is less than the value returned by `exchange` on curve, the transaction will revet. E.g., if curve transfers fewer tokens than it tell us in the returnvalue. 44 | 45 | ### General Properties for both deposit and withdrawal 46 | 47 | - The bridge is synchronous, and will always return `isAsync = false`. 48 | 49 | - _Note_: Because `stEth` is rebasing, we wrap/unwrap it to `wstEth` (wrapped staked ether). This is to ensure that values are as expected when exiting from or transferring within the Rollup. 50 | 51 | - The Bridge perform token pre-approvals in the constructor to allow the `ROLLUP_PROCESSOR`, `WRAPPED_STETH` and `CURVE_POOL` to pull tokens from it. This is to reduce gas-overhead when performing the actions. It is safe to do, as the bridge is not holding funds itself. 52 | 53 | ## Can tokens balances be impacted by external parties, if yes, how? 54 | 55 | As we are using the wrapped variation of `stEth` it will not directly be impacted by rewards or slashing. However, the amount of `stEth` it can be unwrapped to might deviate from the expected if there has been a slashing event. 56 | 57 | ## Is the contract upgradeable? 58 | 59 | No, the bridge is immutable without any admin role. 60 | 61 | ## Does the bridge maintain state? 62 | 63 | No, the bridge don't maintain a state. However, it keeps an insignificant amount of token (dust) in the bridge to reduce gas-costs of future transactions. By having dust, we don't need to do a `sstore` from `0` to `non-zero`. 64 | -------------------------------------------------------------------------------- /specs/bridges/curve/lpbridge/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Curve stEth LP Bridge 2 | 3 | ## What does the bridge do? Why build it? 4 | 5 | The bridge add/remove liquidity to the curve `stEth` pool, allowing users to earn trading fees on their assets. 6 | 7 | ## What protocol(s) does the bridge interact with ? 8 | 9 | The bridge interacts with two protocols, namely Lido and Curve. 10 | 11 | [Lido](https://lido.fi/) is a project that build liquid staking derivatives. They allow users to deposit stakeable assets (Eth, Sol etc) and in return get a representation of the staked asset which will grow with staking rewards. We will only be working with `stEth` (staked ether), so we will be using that for explanations going on. 12 | 13 | `stEth` is a rebasing ERC20 token, and a users balance of it will grow/shrink based on accrued staking rewards or slashing events. After the Merge and the hardfork making it possible to withdraw staked ether from the beacon chain, `stEth` can be burned to redeem an equal amount of `eth`. Until then, `stEth` cannot be redeemed at lido directly, but can instead be traded at a secondary market, such as [curve.fi](https://curve.fi/steth). 14 | 15 | [Curve](https://curve.fi/) is a AMM that specializes in pools with low internal volatility (stableswap). It is at the time of writing, the most liquid market for trading between `stEth` and `eth`. 16 | 17 | ## What is the flow of the bridge? 18 | 19 | There are two main flows of the Curve stEth LP Bridge, namely adding liquidity and remove liquidity. 20 | 21 | ![Curve LP Flow](CurveLp.svg) 22 | 23 | ### Deposit 24 | 25 | The deposit can be done with either `eth` or `wstEth`. If done with `wstEth` the asset will be unwrapped before the liquidity is added to curve. Eth is added directly. In return the bridge will receive an LP token representing the position. These LP tokens are pulled by the rollup. The deposit requires the user to pass in a price that is used to compute the minimum amount of LP token for the given input asset. Note that for `wstEth` the price passed is for the underlying asset `stEth`. 26 | 27 | ### Withdrawal 28 | 29 | The withdrawal is done by using the LP token as the input token, and will return BOTH `eth` and `wstEth` assets. The LP-token will be taken to curve, where the liquidity is removed (`eth` and `stEth` returned to bridge) and `stEth` is then wrapped to `wstEth` before it is pulled by the rollup. 30 | 31 | **Edge cases** 32 | 33 | - Liquidity might leave, skewing the distribution of the returned assets 34 | 35 | ### General Properties for both deposit and withdrawal 36 | 37 | - The bridge is synchronous, and will always return `isAsync = false`. 38 | 39 | - _Note_: Because `stEth` is rebasing, we wrap/unwrap it to `wstEth` (wrapped staked ether). This is to ensure that values are as expected when exiting from or transferring within the Rollup. 40 | 41 | - The bridge performs token pre-approvals in the constructor to allow the `ROLLUP_PROCESSOR`, `WSTETH` and `CURVE_POOL` to pull tokens from it. This reduces gas-overhead when performing the actions. It is safe to do, as the bridge is not holding funds before or after the interaction. 42 | 43 | ## Can tokens balances be impacted by external parties, if yes, how? 44 | 45 | As we are using the wrapped variation of `stEth` it will not directly be impacted by rewards or slashing. However, the amount of `stEth` it can be unwrapped to might deviate from the expected if there has been a slashing event. 46 | 47 | ## Is the contract upgradeable? 48 | 49 | No, the bridge is immutable without any admin role. 50 | 51 | ## Does the bridge maintain state? 52 | 53 | No, the bridge don't maintain a state. However, it keeps an insignificant amount of token (dust) in the bridge to reduce gas-costs of future transactions. By having dust, we don't need to do a `sstore` from `0` to `non-zero`. 54 | -------------------------------------------------------------------------------- /specs/bridges/donation/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Donation Bridge (Group Withdraw) 2 | 3 | ## What does this bridge do? Why did you build it? 4 | 5 | The bridge allows people to do a "group-withdraw" that essentially can be seen as donations to an address on L1, from a group of people within Aztec. 6 | 7 | ## What protocol(s) does the bridge interact with? 8 | 9 | The bridge only interacts with the ERC20 tokens that it are to transfer 10 | 11 | ## What is the flow of the bridge? 12 | 13 | The bridge only support one flow, namely sending funds to the specified address. 14 | The bridge has an internal mapping of `id`s to addresses, and use the `_auxData` to specify the id. 15 | 16 | ## Please list any edge cases that may restrict the usefulness of the bridge or that the bridge explicitly prevents. 17 | 18 | The bridge are forwarding 30K gas to the recipient receive function if transferring eth, so if that is insufficient, it will revert. 19 | 20 | ## How can the accounting of the bridge be impacted by interactions performed by other parties than the bridge? Example, if borrowing, how does it handle liquidations etc. 21 | 22 | The bridge can only be impacted by other parties, if a donation is made to an, at the time, unlisted id. 23 | The expected behaviour from the user perspective would be that the transaction reverts, but it is possible for a searcher (MEV) to frontrun the defi-interaction and list itself as Donee on the bridge to match the id. 24 | In this case, the searcher would get the funds instead of a revert and refund to the rollup. 25 | 26 | ## What functions are available in the [client](../../../client/donation/donation-bridge-data.ts)? 27 | 28 | While there is a client class, it is of little use, as the bridge never expects to receive anything back. 29 | 30 | ## Is this contract upgradable? If so, what are the restrictions on upgradability? 31 | 32 | The contract is immutable and have no admin controls at all. 33 | 34 | ## Does this bridge maintain state? If so, what is stored and why? 35 | 36 | The bridge maintains an append-only mapping of donees. 37 | The mapping is used to allow passing the recipient through the `_auxData` (64 bits). 38 | -------------------------------------------------------------------------------- /specs/bridges/erc4626/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for ERC4626 Bridge 2 | 3 | ## What does this bridge do? Why did you build it? 4 | 5 | The bridge allows people to issue and redeem shares of any ERC4626 vault after the vault is listed in the contract. 6 | 7 | ## What protocol(s) does the bridge interact with? 8 | 9 | Any ERC4626 compatible vault and the underlying assets. 10 | 11 | ## What is the flow of the bridge? 12 | 13 | The bridge only support 2 flows: 14 | 15 | 1. ERC4626 share issuance (this flow gets triggered when `_auxData` = 0), 16 | 2. ERC4626 share redemption (this flow gets triggered when `_auxData` = 1). 17 | 18 | ## Please list any edge cases that may restrict the usefulness of the bridge or that the bridge explicitly prevents. 19 | 20 | Vault has to be listed first in the bridge contract before using the bridge with it. 21 | On top of that, the vault share and asset tokens have to be registered on the RollupProcessor. 22 | 23 | ## How can the accounting of the bridge be impacted by interactions performed by other parties than the bridge? Example, if borrowing, how does it handle liquidations etc. 24 | 25 | The only state the contract works with are the approvals of share and asset tokens. 26 | This could cause damage if we use the EIP-1087 based optimization of seeding bridge's token balances to non-zero values and then a hacker would set approvals on his hacker vault and steal that non-zero balance. 27 | This would cause the bridge to suddenly be 15k gas more expensive to use which could cause the interactions to run out of gas. 28 | This is a griefing attack since the hacker would not gain any value (e.g. 1 wei of WETH is way more costly to steal than is its value). 29 | 30 | Another potential scenario of accounting being affected is if the ERC4626 vault unexpectedly modifies balance of the RollupProcessor (e.g. vault burning RollupProcessor's share balance out of bridge interaction). 31 | 32 | ## Is this contract upgradable? If so, what are the restrictions on upgradability? 33 | 34 | The contract is immutable and have no admin controls at all. 35 | 36 | ## Does this bridge maintain state? If so, what is stored and why? 37 | 38 | The bridge doesn't store any state. 39 | -------------------------------------------------------------------------------- /specs/bridges/lido/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Lido Bridge 2 | 3 | ## What does the bridge do? Why build it? 4 | 5 | The bridge deposits into Lido to receive `stEth` a staked eth derivative that earns a yield from staking rewards at the beaconchain. We build it to allow users to earn yield on their eth. 6 | 7 | ## What protocol(s) does the bridge interact with ? 8 | 9 | The bridge interacts with two protocols, namely Lido and Curve. 10 | 11 | [Lido](https://lido.fi/) is a project that build liquid staking derivatives. They allow users to deposit stakeable assets (Eth, Sol etc) and in return get a representation of the staked asset which will grow with staking rewards. We will only be working with `stEth` (staked ether), so we will be using that for explanations going on. 12 | 13 | `stEth` is a rebasing ERC20 token, and a users balance of it will grow/shrink based on accrued staking rewards or slashing events. After the Merge and the hardfork making it possible to withdraw staked ether from the beacon chain, `stEth` can be burned to redeem an equal amount of `eth`. Until then, `stEth` cannot be redeemed at lido directly, but can instead be traded at a secondary market, such as [curve.fi](https://curve.fi/steth). 14 | 15 | [Curve](https://curve.fi/) is a AMM that specializes in pools with low internal volatility (stableswap). It is at the time of writing, the most liquid market for trading between `stEth` and `eth`. 16 | 17 | ## What is the flow of the bridge? 18 | 19 | There are two flows of Lido Bridge, namely deposits and withdraws. 20 | 21 | ![Lido flows](LidoBridge.svg) 22 | 23 | ### Deposit 24 | 25 | If the bridge receives `eth` as the input token it will deposit it into the Lido contract along a referall address. In return, the bridge will receive `stEth` which it will wrap to `wstEth` before return the tuple `(wstEthAmount, 0, false)` and the rollup pulls the `wstEth` tokens. 26 | 27 | The gas cost E2E for a deposit is ~175K, this is including the transfers to/from the Rollup Processor. 28 | 29 | **Edge cases**: 30 | 31 | - There is a limit on the size of deposits, so a very large whale might not be able to enter 32 | - The limit is subject to change, so it might influence smaller users over time 33 | - If Lido don't return sufficient `stEth` for the given `eth` deposit, the transaction will revert. 34 | 35 | ### Withdrawal 36 | 37 | If the bridge receives `wstEth` as the input token, it will unwrap them to `stEth` before going to curve, where it will swap it (NOTICE: it accepts any slippage). It will then transfer the eth received to the `ROLLUP_PROCESSOR` for the given `interactionNonce`. 38 | 39 | The gas cost E2E for a withdraw is ~250K, this is including the transfers to/from the Rollup Processor. 40 | 41 | **Edge cases** 42 | 43 | - If the balance of the bridge is less than the value returned by `exchange` on curve, the transaction will revet. E.g., if curve transfers fewer tokens than it tell us in the returnvalue. 44 | 45 | ### General Properties for both deposit and withdrawal 46 | 47 | - The bridge is synchronous, and will always return `isAsync = false`. 48 | 49 | - The bridge does not use an `auxData` 50 | 51 | - _Note_: Because `stEth` is rebasing, we wrap/unwrap it to `wstEth` (wrapped staked ether). This is to ensure that values are as expected when exiting from or transferring within the Rollup. 52 | 53 | - The Bridge perform token pre-approvals in the constructor to allow the `ROLLUP_PROCESSOR`, `WRAPPED_STETH` and `CURVE_POOL` to pull tokens from it. This is to reduce gas-overhead when performing the actions. It is safe to do, as the bridge is not holding funds itself. 54 | 55 | ## Can tokens balances be impacted by external parties, if yes, how? 56 | 57 | As we are using the wrapped variation of `stEth` it will not directly be impacted by rewards or slashing. However, the amount of `stEth` it can be unwrapped to might deviate from the expected if there has been a slashing event. 58 | 59 | ## Is the contract upgradeable? 60 | 61 | ## What about withdrawing after the merge and hardfork? 62 | 63 | When Lido can support withdraws directly, a new bridge can be made that performs this interaction. Because the bridge don't hold the tokens, the user is free to take his shielded L2 `wstEth` and go to any other bridge to use them to his liking. 64 | -------------------------------------------------------------------------------- /specs/bridges/liquity/TroveBridge/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Trove Bridge 2 | 3 | ## What does the bridge do? Why build it? 4 | The bridge allows user to borrow LUSD by depositing ETH as collateral. 5 | 6 | ## What protocol(s) does the bridge interact with ? 7 | This bridge interacts with Liquity and Uniswap V3 protocols. 8 | Uniswap is used when user wants to repay debt with collateral (ETH is "flash swapped" to LUSD, debt gets repaid, 9 | collateral withdrawn, flash swap gets paid for with withdrawn collateral). 10 | 11 | ## What is the flow of the bridge? 12 | There are 3 flows supported by the bridge: borrowing, repaying and redeeming. 13 | 14 | > Note: Before the bridge gets used someone has to open the bridge's Trove by calling bridge's `openTrove` function. 15 | 16 | ### Borrowing 17 | Borrowing flow is simple. 18 | User provides ETH on the input and gets LUSD on the ouput (+ accounting token used to rerpresent user's collateral and 19 | debt). 20 | Since the collateral ratio is fixed by the bridge, user gets the amount of LUSD out based only on the amount 21 | of collateral provided and the collateral ratio. 22 | The borrowing interaction would revert in case the bridge's Trove is not active. 23 | 24 | > Note: Fixed collateral ratio in this case means that no user can ever move the collateral ratio of the bridge's Trove. 25 | > The collateral ratio can only be affected by the market movements (change of ETH price). 26 | 27 | ### Repaying 28 | 29 | There are 3 repaying "subflows": 30 | 1. Repaying with LUSD -> User provides LUSD (and accounting token) on input and gets the full amount of collateral 31 | originally provided, 32 | 2. Repaying with collateral -> User repays the debt with collateral using flash swaps. 33 | 3. Repaying with a combination of LUSD and collateral -> This flow gets executed when the Trove managed by the bridge 34 | was part of a [redistribution](https://www.liquity.org/features/efficient-liquidations). 35 | In such a case 1 accounting token corresponds to more than one LUSD worth of debt. 36 | Due to limitations of Aztec Connect both input tokens have the same amount on the input. 37 | This means that it's currently impossible to provide more of LUSD than accounting token on input which means that 38 | in that not enough LUSD was provided to repay the debt in full. 39 | For this reason flash swap of a part of user's collateral is performed. 40 | This is an edge case scenario which might never occur. 41 | 42 | > Note: Currently only the second subflow is used (repaying with collateral) because it turned out to be complicated 43 | to provide the same amount of input tokens on the input (for that we would need user to have notes of the same value 44 | of both tokens -> this basically never happens which means that user would need to first split one of her notes -> 45 | this would require a standalone transaction and user would have to wait for the tx to be settled -> this is a horrible 46 | UX, so we've decided to currently only support the subflow 2 on the zk.money). 47 | 48 | ### Redeeming 49 | This is a flow which gets executed when the Trove was closed by redemption (see [liquity blog](https://www.liquity.org/blog/understanding-liquitys-redemption-mechanism) for explanation). 50 | In such a scenario user only provides accounting token on the input and receives the remaining collateral on the output. 51 | 52 | ### General Properties of flows 53 | 54 | - The bridge is synchronous, and will always return `isAsync = false`. 55 | 56 | - The bridge uses an `auxData` to pass in the maximum borrower fee during the borrowing flow or max price during 57 | the repaying with collateral flow and repaying after redistribution flows. 58 | For repaying with LUSD and redeeming flows `auxData` is unused. 59 | 60 | - The Bridge perform token pre-approvals in the `openTrove` function. 61 | 62 | ## How many Troves does 1 bridge controls? 63 | 1 deployment of the bridge contract controls 1 trove. 64 | The bridge keeps precise accounting of debt by making sure that no user can change the trove's ICR. 65 | This means that when a price goes down the only way how a user can avoid liquidation penalty is to repay their debt. 66 | This is limiting and a bit unfortunate since borrowing fee gets paid only once and that is during borrowing. 67 | 68 | ## Other relevant info 69 | 70 | ## Liquidation 71 | In case the trove gets liquidated, the bridge no longer controls any ETH and all the TB balances are irrelevant. 72 | At this point the bridge is defunct (unless owner is the only one who borrowed). 73 | If owner is the only who borrowed calling `closeTrove()` will succeed and owner's balance will get burned, making total 74 | supply of accounting token 0. 75 | 76 | ## Liquity recovery mode 77 | Users are not able to exit the Trove in case the Liquity system is in recovery mode (total CR < 150%). 78 | This is because in recovery mode only pure collateral top-up or debt repayment is allowed. 79 | This makes exit from this bridge impossible in recovery mode because such exit is always a combination of debt 80 | repayment and collateral withdrawal. 81 | 82 | ## How can the accounting of the bridge be impacted by interactions performed by other parties than the bridge? 83 | These are the outside influences which can affect the bridge: 84 | 1. ETH price movement, 85 | 2. Trove redemption, 86 | 3. debt redistribution, 87 | 4. liquidity in the LUSD/USDC and USDC/ETH 500 bps fee tier pools. 88 | 89 | ## Is this contract upgradable? 90 | No 91 | 92 | ## Does this bridge maintain state? If so, what is stored and why? 93 | Yes, the bridge itself is an ERC20 token and the bridge token balances are used for accounting. -------------------------------------------------------------------------------- /specs/bridges/uniswap/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Uniswap Bridge 2 | 3 | ## What does the bridge do? Why build it? 4 | 5 | The bridge swaps `_inputAssetA` for `_outputAssetA` along the path specified in `_auxData`. 6 | Encoding of a path allows for up to 2 split paths (see documentation in UniswapBridge.sol for details) and up to 3 pools (2 middle tokens) in each split path. 7 | 8 | ## What protocol(s) does the bridge interact with ? 9 | 10 | The bridge interacts with [Uniswap v3](https://docs.uniswap.org/protocol/introduction). 11 | 12 | ## What is the flow of the bridge? 13 | 14 | There is only 1 flow in the bridge. 15 | In this flow `_inputAssetA` is swapped for `_outputAssetA` along the path specified in `_auxData` 16 | 17 | **Edge cases**: 18 | 19 | - Interaction might revert in case the minimum acceptable price is set too high or the price of the output asset moves up before the interaction settles. 20 | - Users might get sandwiched in case the minimum acceptable price is set too low or the price of the output token goes down before the interaction settles making the users lose positive slippage. 21 | 22 | ### General Properties of convert(...) function 23 | 24 | - The bridge is synchronous, and will always return `isAsync = false`. 25 | 26 | - The bridge uses `_auxData` to encode swap path. 27 | Details on the encoding are in the bridge's NatSpec documentation. 28 | 29 | - The Bridge perform token pre-approvals to allow the `ROLLUP_PROCESSOR` and `UNI_ROUTER` to pull tokens from it. 30 | This is to reduce gas-overhead when performing the actions. It is safe to do, as the bridge is not holding the funds itself. 31 | 32 | ## Is the contract upgradeable? 33 | 34 | No, the bridge is immutable without any admin role. 35 | 36 | ## Does the bridge maintain state? 37 | 38 | No, the bridge doesn't maintain a state. 39 | However, it keeps an insignificant amount of tokens (dust) in the bridge to reduce gas-costs of future transactions (in case the DUST was sent to the bridge). 40 | By having a dust, we don't need to do a `sstore` from `0` to `non-zero`. 41 | -------------------------------------------------------------------------------- /specs/bridges/yearn/readme.md: -------------------------------------------------------------------------------- 1 | # Spec for Yearn Bridge 2 | 3 | ## What does the bridge do? Why build it? 4 | 5 | The bridge deposits an ERC20 token into the corresponding Yearn Vault, and receives another ERC20 called yvToken that represents its deposit in the vault. 6 | The tokens deposited into the vault are going to be invested using different strategies, with different capital allocations based on risk and profitability. 7 | This will accrue yield and be reflected by an increase in the `pricePerShare` of the yvToken. 8 | 9 | ## What protocol(s) does the bridge interact with ? 10 | 11 | The bridge will only interact with Yearn Vaults. 12 | 13 | ## What is the flow of the bridge? 14 | 15 | Users will use the bridge in two cases: deposit and withdraw. 16 | 17 | ### Deposit 18 | 19 | When the bridge proceed to deposit the input token to the output vault. 20 | 21 | If the bridge receives `ETH` as the input token it will first wrap into `WETH` and then follow the same flow as any other ERC20. 22 | 23 | We check that `auxData` is correct (`0`), `inputValue` is greater that 0 and that the token is an ERC20. After that, the bridge calls the `deposit` function to send the tokens to the vault and receive yvTokens as a receipt for it. 24 | 25 | The gas cost for ERC20 deposit is ~230k. 26 | The gas cost for ETH deposit is ~118k. 27 | 28 | ### Withdrawal 29 | 30 | When the bridge receives a withdrawal request with a yvToken as `inputAssetA`, the bridge calls the `withdraw` function of the contract. This will burn the yvTokens and send back the principal plus the yield accrued. The amount of underlying to be received is equal to the amount of yvTokens times `pricePerShare`. 31 | 32 | If the supplied `outputAssetA` is `ETH`, we follow the same flow as any other ERC20, and at the end we unwrap `WETH` into `ETH` before sending them to the `ROLLUP_PROCESSOR` for the given `interactionNonce`. 33 | 34 | The gas cost for ERC20 withdrawal is ~225k. 35 | The gas cost for ETH withdrawal is ~238k. 36 | 37 | ### General Properties for both deposit and withdrawal 38 | 39 | - The bridge is synchronous, and will always return `isAsync = false`. 40 | 41 | - The bridge uses `auxData` where `0` means `deposit` and `1` means `withdrawal`. 42 | 43 | - The bridge performs infinite token approvals in the constructor to allow all the required tokens. There's also a function to approve a specific Vault to handle new deployments. Infinite approvals are safe because the bridge doesn't hold any funds. 44 | 45 | ## Can tokens balances be impacted by external parties, if yes, how? 46 | 47 | The number of shares received from the vault is not affected by any external party. 48 | 49 | On withdrawal, the number of tokens received will depend on the `pricePerShare`, which is usually higher than when the user deposited. 50 | 51 | ## Is the contract upgradeable? 52 | 53 | No, the bridge is immutable without any admin role. 54 | 55 | ## Does the bridge maintain state? 56 | 57 | No, the bridge doesn't maintain a state. 58 | -------------------------------------------------------------------------------- /src/aztec/interfaces/IDefiBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec 3 | pragma solidity >=0.8.4; 4 | 5 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 6 | 7 | interface IDefiBridge { 8 | /** 9 | * @notice A function which converts input assets to output assets. 10 | * @param _inputAssetA A struct detailing the first input asset 11 | * @param _inputAssetB A struct detailing the second input asset 12 | * @param _outputAssetA A struct detailing the first output asset 13 | * @param _outputAssetB A struct detailing the second output asset 14 | * @param _totalInputValue An amount of input assets transferred to the bridge (Note: "total" is in the name 15 | * because the value can represent summed/aggregated token amounts of users actions on L2) 16 | * @param _interactionNonce A globally unique identifier of this interaction/`convert(...)` call. 17 | * @param _auxData Bridge specific data to be passed into the bridge contract (e.g. slippage, nftID etc.) 18 | * @return outputValueA An amount of `_outputAssetA` returned from this interaction. 19 | * @return outputValueB An amount of `_outputAssetB` returned from this interaction. 20 | * @return isAsync A flag indicating if the interaction is async. 21 | * @dev This function is called from the RollupProcessor contract via the DefiBridgeProxy. Before this function is 22 | * called _RollupProcessor_ contract will have sent you all the assets defined by the input params. This 23 | * function is expected to convert input assets to output assets (e.g. on Uniswap) and return the amounts 24 | * of output assets to be received by the _RollupProcessor_. If output assets are ERC20 tokens the bridge has 25 | * to _RollupProcessor_ as a spender before the interaction is finished. If some of the output assets is ETH 26 | * it has to be sent to _RollupProcessor_ via the `receiveEthFromBridge(uint256 _interactionNonce)` method 27 | * inside before the `convert(...)` function call finishes. 28 | * @dev If there are two input assets, equal amounts of both assets will be transferred to the bridge before this 29 | * method is called. 30 | * @dev **BOTH** output assets could be virtual but since their `assetId` is currently assigned as 31 | * `_interactionNonce` it would simply mean that more of the same virtual asset is minted. 32 | * @dev If this interaction is async the function has to return `(0,0 true)`. Async interaction will be finalised at 33 | * a later time and its output assets will be returned in a `IDefiBridge.finalise(...)` call. 34 | * 35 | */ 36 | function convert( 37 | AztecTypes.AztecAsset calldata _inputAssetA, 38 | AztecTypes.AztecAsset calldata _inputAssetB, 39 | AztecTypes.AztecAsset calldata _outputAssetA, 40 | AztecTypes.AztecAsset calldata _outputAssetB, 41 | uint256 _totalInputValue, 42 | uint256 _interactionNonce, 43 | uint64 _auxData, 44 | address _rollupBeneficiary 45 | ) external payable returns (uint256 outputValueA, uint256 outputValueB, bool isAsync); 46 | 47 | /** 48 | * @notice A function that finalises asynchronous interaction. 49 | * @param _inputAssetA A struct detailing the first input asset 50 | * @param _inputAssetB A struct detailing the second input asset 51 | * @param _outputAssetA A struct detailing the first output asset 52 | * @param _outputAssetB A struct detailing the second output asset 53 | * @param _interactionNonce A globally unique identifier of this interaction/`convert(...)` call. 54 | * @param _auxData Bridge specific data to be passed into the bridge contract (e.g. slippage, nftID etc.) 55 | * @return outputValueA An amount of `_outputAssetA` returned from this interaction. 56 | * @return outputValueB An amount of `_outputAssetB` returned from this interaction. 57 | * @dev This function should use the `BridgeBase.onlyRollup()` modifier to ensure it can only be called from 58 | * the `RollupProcessor.processAsyncDefiInteraction(uint256 _interactionNonce)` method. 59 | * 60 | */ 61 | function finalise( 62 | AztecTypes.AztecAsset calldata _inputAssetA, 63 | AztecTypes.AztecAsset calldata _inputAssetB, 64 | AztecTypes.AztecAsset calldata _outputAssetA, 65 | AztecTypes.AztecAsset calldata _outputAssetB, 66 | uint256 _interactionNonce, 67 | uint64 _auxData 68 | ) external payable returns (uint256 outputValueA, uint256 outputValueB, bool interactionComplete); 69 | } 70 | -------------------------------------------------------------------------------- /src/aztec/interfaces/ISubsidy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec 3 | pragma solidity >=0.8.4; 4 | 5 | // @dev documentation of this interface is in its implementation (Subsidy contract) 6 | interface ISubsidy { 7 | /** 8 | * @notice Container for Subsidy related information 9 | * @member available Amount of ETH remaining to be paid out 10 | * @member gasUsage Amount of gas the interaction consumes (used to define max possible payout) 11 | * @member minGasPerMinute Minimum amount of gas per minute the subsidizer has to subsidize 12 | * @member gasPerMinute Amount of gas per minute the subsidizer is willing to subsidize 13 | * @member lastUpdated Last time subsidy was paid out or funded (if not subsidy was yet claimed after funding) 14 | */ 15 | struct Subsidy { 16 | uint128 available; 17 | uint32 gasUsage; 18 | uint32 minGasPerMinute; 19 | uint32 gasPerMinute; 20 | uint32 lastUpdated; 21 | } 22 | 23 | function setGasUsageAndMinGasPerMinute(uint256 _criteria, uint32 _gasUsage, uint32 _minGasPerMinute) external; 24 | 25 | function setGasUsageAndMinGasPerMinute( 26 | uint256[] calldata _criteria, 27 | uint32[] calldata _gasUsage, 28 | uint32[] calldata _minGasPerMinute 29 | ) external; 30 | 31 | function registerBeneficiary(address _beneficiary) external; 32 | 33 | function subsidize(address _bridge, uint256 _criteria, uint32 _gasPerMinute) external payable; 34 | 35 | function topUp(address _bridge, uint256 _criteria) external payable; 36 | 37 | function claimSubsidy(uint256 _criteria, address _beneficiary) external returns (uint256); 38 | 39 | function withdraw(address _beneficiary) external returns (uint256); 40 | 41 | // solhint-disable-next-line 42 | function MIN_SUBSIDY_VALUE() external view returns (uint256); 43 | 44 | function claimableAmount(address _beneficiary) external view returns (uint256); 45 | 46 | function isRegistered(address _beneficiary) external view returns (bool); 47 | 48 | function getSubsidy(address _bridge, uint256 _criteria) external view returns (Subsidy memory); 49 | 50 | function getAccumulatedSubsidyAmount(address _bridge, uint256 _criteria) external view returns (uint256); 51 | } 52 | -------------------------------------------------------------------------------- /src/bridges/base/BridgeBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IDefiBridge} from "../../aztec/interfaces/IDefiBridge.sol"; 6 | import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {ErrorLib} from "./ErrorLib.sol"; 9 | 10 | /** 11 | * @title BridgeBase 12 | * @notice A base that bridges can be built upon which imports a limited set of features 13 | * @dev Reverts `convert` with missing implementation, and `finalise` with async disabled 14 | * @author Lasse Herskind 15 | */ 16 | abstract contract BridgeBase is IDefiBridge { 17 | error MissingImplementation(); 18 | 19 | ISubsidy public constant SUBSIDY = ISubsidy(0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA); 20 | address public immutable ROLLUP_PROCESSOR; 21 | 22 | constructor(address _rollupProcessor) { 23 | ROLLUP_PROCESSOR = _rollupProcessor; 24 | } 25 | 26 | modifier onlyRollup() { 27 | if (msg.sender != ROLLUP_PROCESSOR) { 28 | revert ErrorLib.InvalidCaller(); 29 | } 30 | _; 31 | } 32 | 33 | function convert( 34 | AztecTypes.AztecAsset calldata, 35 | AztecTypes.AztecAsset calldata, 36 | AztecTypes.AztecAsset calldata, 37 | AztecTypes.AztecAsset calldata, 38 | uint256, 39 | uint256, 40 | uint64, 41 | address 42 | ) external payable virtual override(IDefiBridge) returns (uint256, uint256, bool) { 43 | revert MissingImplementation(); 44 | } 45 | 46 | function finalise( 47 | AztecTypes.AztecAsset calldata, 48 | AztecTypes.AztecAsset calldata, 49 | AztecTypes.AztecAsset calldata, 50 | AztecTypes.AztecAsset calldata, 51 | uint256, 52 | uint64 53 | ) external payable virtual override(IDefiBridge) returns (uint256, uint256, bool) { 54 | revert ErrorLib.AsyncDisabled(); 55 | } 56 | 57 | /** 58 | * @notice Computes the criteria that is passed on to the subsidy contract when claiming 59 | * @dev Should be overridden by bridge implementation if intended to limit subsidy. 60 | * @return The criteria to be passed along 61 | */ 62 | function computeCriteria( 63 | AztecTypes.AztecAsset calldata, 64 | AztecTypes.AztecAsset calldata, 65 | AztecTypes.AztecAsset calldata, 66 | AztecTypes.AztecAsset calldata, 67 | uint64 68 | ) public view virtual returns (uint256) { 69 | return 0; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/bridges/base/ErrorLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | library ErrorLib { 6 | error InvalidCaller(); 7 | 8 | error InvalidInput(); 9 | error InvalidInputA(); 10 | error InvalidInputB(); 11 | error InvalidOutputA(); 12 | error InvalidOutputB(); 13 | error InvalidInputAmount(); 14 | error InvalidAuxData(); 15 | 16 | error ApproveFailed(address token); 17 | error TransferFailed(address token); 18 | 19 | error InvalidNonce(); 20 | error AsyncDisabled(); 21 | } 22 | -------------------------------------------------------------------------------- /src/bridges/curve/Deployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | contract Deployer { 6 | function deploy(bytes memory _bytecode) public returns (address deployedAddress) { 7 | assembly { 8 | deployedAddress := create(0, add(_bytecode, 0x20), mload(_bytecode)) 9 | } 10 | if (deployedAddress == address(0)) { 11 | revert("Contract not deployed"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/bridges/dca/SafeCastLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | library SafeCastLib { 6 | function toU128(uint256 _a) internal pure returns (uint128) { 7 | if (_a > type(uint128).max) { 8 | revert("Overflow"); 9 | } 10 | return uint128(_a); 11 | } 12 | 13 | function toU120(uint256 _a) internal pure returns (uint120) { 14 | if (_a > type(uint120).max) { 15 | revert("Overflow"); 16 | } 17 | return uint120(_a); 18 | } 19 | 20 | function toU32(uint256 _a) internal pure returns (uint32) { 21 | if (_a > type(uint32).max) { 22 | revert("Overflow"); 23 | } 24 | return uint32(_a); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/bridges/dca/UniswapDCABridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | 8 | import {IWETH} from "../../interfaces/IWETH.sol"; 9 | import {IChainlinkOracle} from "../../interfaces/chainlink/IChainlinkOracle.sol"; 10 | import {ISwapRouter} from "../../interfaces/uniswapv3/ISwapRouter.sol"; 11 | import {BiDCABridge} from "./BiDCABridge.sol"; 12 | 13 | /** 14 | * @notice Initial implementation of the BiDCA bridge using Uniswap as the DEX and Chainlink as oracle. 15 | * The bridge is using DAI and WETH for A and B with a Chainlink oracle to get prices. 16 | * The bridge allows users to force a rebalance through Uniswap pools. 17 | * The forced rebalance will: 18 | * 1. rebalance internally in the ticks, as the BiDCABridge, 19 | * 2. rebalance cross-ticks, e.g., excess from the individual ticks are matched, 20 | * 3. swap any remaining excess using Uniswap, and rebalance with the returned assets 21 | * @dev The slippage + path is immutable, so low liquidity in Uniswap might block the `rebalanceAndfillUniswap` flow. 22 | * @author Lasse Herskind (LHerskind on GitHub). 23 | */ 24 | contract UniswapDCABridge is BiDCABridge { 25 | using SafeERC20 for IERC20; 26 | 27 | error NegativePrice(); 28 | 29 | address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; 30 | address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; 31 | 32 | uint160 internal constant SQRT_PRICE_LIMIT_X96 = 1461446703485210103287273052203988822378723970341; 33 | ISwapRouter public constant UNI_ROUTER = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564); 34 | 35 | uint256 public constant SLIPPAGE = 100; // Basis points 36 | 37 | IChainlinkOracle public constant ORACLE = IChainlinkOracle(0x773616E4d11A78F511299002da57A0a94577F1f4); 38 | 39 | constructor(address _rollupProcessor, uint256 _tickSize, uint256 _fee) 40 | BiDCABridge(_rollupProcessor, DAI, address(WETH), _tickSize, _fee) 41 | { 42 | IERC20(DAI).safeApprove(address(UNI_ROUTER), type(uint256).max); 43 | IERC20(address(WETH)).safeApprove(address(UNI_ROUTER), type(uint256).max); 44 | } 45 | 46 | function rebalanceAndFillUniswap() public returns (int256, int256) { 47 | rebalanceAndFillUniswap(type(uint256).max); 48 | } 49 | 50 | /** 51 | * @notice Rebalances within ticks, then across ticks, and finally, take the remaining funds to uniswap 52 | * where it is traded for the opposite, and used to rebalance completely 53 | * @dev Uses a specific path for the assets to do the swap 54 | * @dev Slippage protection through the chainlink oracle, as a base price 55 | * @dev Can be quite gas intensive as it will loop multiple times over the ticks to fill orders. 56 | * @return aFlow The flow of token A 57 | * @return bFlow The flow of token B 58 | */ 59 | function rebalanceAndFillUniswap(uint256 _upperTick) public returns (int256, int256) { 60 | uint256 oraclePrice = getPrice(); 61 | (int256 aFlow, int256 bFlow, uint256 a, uint256 b) = _rebalanceAndFill(0, 0, oraclePrice, _upperTick, true); 62 | 63 | // If we have available A and B, we can do internal rebalancing across ticks with these values. 64 | if (a > 0 && b > 0) { 65 | (aFlow, bFlow, a, b) = _rebalanceAndFill(a, b, oraclePrice, _upperTick, true); 66 | } 67 | 68 | if (a > 0) { 69 | // Trade all A to B using uniswap. 70 | uint256 bOffer = UNI_ROUTER.exactInput( 71 | ISwapRouter.ExactInputParams({ 72 | path: abi.encodePacked(ASSET_A, uint24(100), USDC, uint24(500), ASSET_B), 73 | recipient: address(this), 74 | deadline: block.timestamp, 75 | amountIn: a, 76 | amountOutMinimum: (denominateAssetAInB(a, oraclePrice, false) * (10000 - SLIPPAGE)) / 10000 77 | }) 78 | ); 79 | 80 | // Rounding DOWN ensures that B received / price >= A available 81 | uint256 price = (bOffer * 1e18) / a; 82 | 83 | (aFlow, bFlow,,) = _rebalanceAndFill(0, bOffer, price, _upperTick, true); 84 | } 85 | 86 | if (b > 0) { 87 | // Trade all B to A using uniswap. 88 | uint256 aOffer = UNI_ROUTER.exactInput( 89 | ISwapRouter.ExactInputParams({ 90 | path: abi.encodePacked(ASSET_B, uint24(500), USDC, uint24(100), ASSET_A), 91 | recipient: address(this), 92 | deadline: block.timestamp, 93 | amountIn: b, 94 | amountOutMinimum: (denominateAssetBInA(b, oraclePrice, false) * (10000 - SLIPPAGE)) / 10000 95 | }) 96 | ); 97 | 98 | // Rounding UP to ensure that A received * price >= B available 99 | uint256 price = (b * 1e18 + aOffer - 1) / aOffer; 100 | 101 | (aFlow, bFlow,,) = _rebalanceAndFill(aOffer, 0, price, _upperTick, true); 102 | } 103 | 104 | return (aFlow, bFlow); 105 | } 106 | 107 | /** 108 | * @notice Fetch the price from the chainlink oracle. 109 | * @dev Reverts if the price is stale or negative 110 | * @return Price 111 | */ 112 | function getPrice() public virtual override(BiDCABridge) returns (uint256) { 113 | (, int256 answer,,,) = ORACLE.latestRoundData(); 114 | if (answer < 0) { 115 | revert NegativePrice(); 116 | } 117 | 118 | return uint256(answer); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/bridges/donation/DonationBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 7 | 8 | import {BridgeBase} from "../base/BridgeBase.sol"; 9 | import {ErrorLib} from "../base/ErrorLib.sol"; 10 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 11 | 12 | /** 13 | * @notice Bridge that allows users to collectively donate funds to an L1 address 14 | * @author Lasse Herskind (LHerskind on GitHub) 15 | */ 16 | contract DonationBridge is BridgeBase { 17 | using SafeERC20 for IERC20; 18 | 19 | error InvalidDoneeAddress(); 20 | error EthTransferFailed(); 21 | 22 | event ListedDonee(address donee, uint64 index); 23 | 24 | // Starts at 1 to revert if users forget to provide auxdata. 25 | uint64 public nextDonee = 1; 26 | 27 | // Maps id to a donee 28 | mapping(uint64 => address) public donees; 29 | 30 | constructor(address _rollupProcessor) BridgeBase(_rollupProcessor) {} 31 | 32 | /** 33 | * @notice Lists a new Donee on the bridge 34 | * @param _donee The address to add as a donee 35 | * @return id The id of the new donee 36 | */ 37 | function listDonee(address _donee) public returns (uint256) { 38 | if (_donee == address(0)) revert InvalidDoneeAddress(); 39 | uint64 id = nextDonee++; 40 | donees[id] = _donee; 41 | emit ListedDonee(_donee, id); 42 | return id; 43 | } 44 | 45 | /** 46 | * @notice Transfers `_inputAssetA` to `donees[_auxData]` 47 | * @param _inputAssetA The asset to donate 48 | * @param _totalInputValue The amount to donate 49 | * @param _auxData The id of the donee 50 | */ 51 | function convert( 52 | AztecTypes.AztecAsset calldata _inputAssetA, 53 | AztecTypes.AztecAsset calldata, 54 | AztecTypes.AztecAsset calldata, 55 | AztecTypes.AztecAsset calldata, 56 | uint256 _totalInputValue, 57 | uint256, 58 | uint64 _auxData, 59 | address 60 | ) external payable override(BridgeBase) onlyRollup returns (uint256, uint256, bool) { 61 | address receiver = donees[_auxData]; 62 | 63 | if (receiver == address(0)) { 64 | revert ErrorLib.InvalidAuxData(); 65 | } 66 | 67 | if (_inputAssetA.assetType == AztecTypes.AztecAssetType.ETH) { 68 | //solhint-disable-next-line 69 | (bool success,) = payable(receiver).call{gas: 30000, value: _totalInputValue}(""); 70 | if (!success) revert EthTransferFailed(); 71 | } else if (_inputAssetA.assetType == AztecTypes.AztecAssetType.ERC20) { 72 | IERC20(_inputAssetA.erc20Address).safeTransfer(receiver, _totalInputValue); 73 | } else { 74 | revert ErrorLib.InvalidInputA(); 75 | } 76 | return (0, 0, false); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/bridges/example/ExampleBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 7 | import {ErrorLib} from "../base/ErrorLib.sol"; 8 | import {BridgeBase} from "../base/BridgeBase.sol"; 9 | 10 | /** 11 | * @title An example bridge contract. 12 | * @author Aztec Team 13 | * @notice You can use this contract to immediately get back what you've deposited. 14 | * @dev This bridge demonstrates the flow of assets in the convert function. This bridge simply returns what has been 15 | * sent to it. 16 | */ 17 | contract ExampleBridge is BridgeBase { 18 | /** 19 | * @notice Set address of rollup processor 20 | * @param _rollupProcessor Address of rollup processor 21 | */ 22 | constructor(address _rollupProcessor) BridgeBase(_rollupProcessor) { 23 | address dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F; 24 | address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; 25 | 26 | uint256[] memory criterias = new uint256[](2); 27 | uint32[] memory gasUsage = new uint32[](2); 28 | uint32[] memory minGasPerMinute = new uint32[](2); 29 | 30 | criterias[0] = uint256(keccak256(abi.encodePacked(dai, dai))); 31 | criterias[1] = uint256(keccak256(abi.encodePacked(usdc, usdc))); 32 | 33 | gasUsage[0] = 72896; 34 | gasUsage[1] = 80249; 35 | 36 | minGasPerMinute[0] = 100; 37 | minGasPerMinute[1] = 150; 38 | 39 | // We set gas usage in the subsidy contract 40 | // We only want to incentivize the bridge when input and output token is Dai or USDC 41 | SUBSIDY.setGasUsageAndMinGasPerMinute(criterias, gasUsage, minGasPerMinute); 42 | } 43 | 44 | /** 45 | * @notice A function which returns an _totalInputValue amount of _inputAssetA 46 | * @param _inputAssetA - Arbitrary ERC20 token 47 | * @param _outputAssetA - Equal to _inputAssetA 48 | * @param _rollupBeneficiary - Address of the contract which receives subsidy in case subsidy was set for a given 49 | * criteria 50 | * @return outputValueA - the amount of output asset to return 51 | * @dev In this case _outputAssetA equals _inputAssetA 52 | */ 53 | function convert( 54 | AztecTypes.AztecAsset calldata _inputAssetA, 55 | AztecTypes.AztecAsset calldata _inputAssetB, 56 | AztecTypes.AztecAsset calldata _outputAssetA, 57 | AztecTypes.AztecAsset calldata _outputAssetB, 58 | uint256 _totalInputValue, 59 | uint256, 60 | uint64 _auxData, 61 | address _rollupBeneficiary 62 | ) external payable override(BridgeBase) onlyRollup returns (uint256 outputValueA, uint256, bool) { 63 | // Check the input asset is ERC20 64 | if (_inputAssetA.assetType != AztecTypes.AztecAssetType.ERC20) revert ErrorLib.InvalidInputA(); 65 | if (_outputAssetA.erc20Address != _inputAssetA.erc20Address) revert ErrorLib.InvalidOutputA(); 66 | // Return the input value of input asset 67 | outputValueA = _totalInputValue; 68 | // Approve rollup processor to take input value of input asset 69 | IERC20(_outputAssetA.erc20Address).approve(ROLLUP_PROCESSOR, _totalInputValue); 70 | 71 | // Pay out subsidy to the rollupBeneficiary 72 | SUBSIDY.claimSubsidy( 73 | computeCriteria(_inputAssetA, _inputAssetB, _outputAssetA, _outputAssetB, _auxData), _rollupBeneficiary 74 | ); 75 | } 76 | 77 | /** 78 | * @notice Computes the criteria that is passed when claiming subsidy. 79 | * @param _inputAssetA The input asset 80 | * @param _outputAssetA The output asset 81 | * @return The criteria 82 | */ 83 | function computeCriteria( 84 | AztecTypes.AztecAsset calldata _inputAssetA, 85 | AztecTypes.AztecAsset calldata, 86 | AztecTypes.AztecAsset calldata _outputAssetA, 87 | AztecTypes.AztecAsset calldata, 88 | uint64 89 | ) public view override(BridgeBase) returns (uint256) { 90 | return uint256(keccak256(abi.encodePacked(_inputAssetA.erc20Address, _outputAssetA.erc20Address))); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/bridges/lido/LidoBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import {ICurvePool} from "../../interfaces/curve/ICurvePool.sol"; 6 | import {ILido} from "../../interfaces/lido/ILido.sol"; 7 | import {IWstETH} from "../../interfaces/lido/IWstETH.sol"; 8 | import {IRollupProcessor} from "rollup-encoder/interfaces/IRollupProcessor.sol"; 9 | 10 | import {BridgeBase} from "../base/BridgeBase.sol"; 11 | import {ErrorLib} from "../base/ErrorLib.sol"; 12 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 13 | import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 14 | 15 | contract LidoBridge is BridgeBase { 16 | using SafeERC20 for ILido; 17 | using SafeERC20 for IWstETH; 18 | 19 | error InvalidConfiguration(); 20 | error InvalidWrapReturnValue(); 21 | error InvalidUnwrapReturnValue(); 22 | 23 | address public immutable REFERRAL; 24 | 25 | ILido public constant LIDO = ILido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); 26 | IWstETH public constant WRAPPED_STETH = IWstETH(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0); 27 | ICurvePool public constant CURVE_POOL = ICurvePool(0xDC24316b9AE028F1497c275EB9192a3Ea0f67022); 28 | 29 | int128 private constant CURVE_ETH_INDEX = 0; 30 | int128 private constant CURVE_STETH_INDEX = 1; 31 | 32 | // The amount of dust to leave in the contract 33 | uint256 private constant DUST = 1; 34 | 35 | constructor(address _rollupProcessor, address _referral) BridgeBase(_rollupProcessor) { 36 | if (CURVE_POOL.coins(uint256(uint128(CURVE_STETH_INDEX))) != address(LIDO)) { 37 | revert InvalidConfiguration(); 38 | } 39 | 40 | REFERRAL = _referral; 41 | 42 | // As the contract is not supposed to hold any funds, we can pre-approve 43 | LIDO.safeIncreaseAllowance(address(WRAPPED_STETH), type(uint256).max); 44 | LIDO.safeIncreaseAllowance(address(CURVE_POOL), type(uint256).max); 45 | WRAPPED_STETH.safeIncreaseAllowance(ROLLUP_PROCESSOR, type(uint256).max); 46 | } 47 | 48 | receive() external payable {} 49 | 50 | function convert( 51 | AztecTypes.AztecAsset calldata _inputAssetA, 52 | AztecTypes.AztecAsset calldata, 53 | AztecTypes.AztecAsset calldata _outputAssetA, 54 | AztecTypes.AztecAsset calldata, 55 | uint256 _totalInputValue, 56 | uint256 _interactionNonce, 57 | uint64, 58 | address 59 | ) external payable override(BridgeBase) onlyRollup returns (uint256 outputValueA, uint256, bool isAsync) { 60 | bool isETHInput = _inputAssetA.assetType == AztecTypes.AztecAssetType.ETH; 61 | bool isWstETHInput = _inputAssetA.assetType == AztecTypes.AztecAssetType.ERC20 62 | && _inputAssetA.erc20Address == address(WRAPPED_STETH); 63 | 64 | if (!(isETHInput || isWstETHInput)) { 65 | revert ErrorLib.InvalidInputA(); 66 | } 67 | 68 | isAsync = false; 69 | outputValueA = isETHInput 70 | ? _wrapETH(_totalInputValue, _outputAssetA) 71 | : _unwrapETH(_totalInputValue, _outputAssetA, _interactionNonce); 72 | } 73 | 74 | /** 75 | * Convert ETH -> wstETH 76 | */ 77 | function _wrapETH(uint256 _totalInputValue, AztecTypes.AztecAsset calldata _outputAsset) 78 | private 79 | returns (uint256 outputValue) 80 | { 81 | if ( 82 | _outputAsset.assetType != AztecTypes.AztecAssetType.ERC20 83 | || _outputAsset.erc20Address != address(WRAPPED_STETH) 84 | ) { 85 | revert ErrorLib.InvalidOutputA(); 86 | } 87 | 88 | // deposit into lido (return value is shares NOT stETH) 89 | LIDO.submit{value: _totalInputValue}(REFERRAL); 90 | 91 | // Leave `DUST` in the stEth balance to save gas on future runs 92 | uint256 outputStETHBalance = LIDO.balanceOf(address(this)) - DUST; 93 | 94 | // Lido balance can be <=2 wei off, 1 from the submit where our shares is computed rounding down, 95 | // and then again when the balance is computed from the shares, rounding down again. 96 | if (outputStETHBalance + 2 + DUST < _totalInputValue) { 97 | revert InvalidWrapReturnValue(); 98 | } 99 | 100 | // since stETH is a rebase token, lets wrap it to wstETH before sending it back to the rollupProcessor. 101 | // Again, leave `DUST` in the wstEth balance to save gas on future runs 102 | outputValue = WRAPPED_STETH.wrap(outputStETHBalance) - DUST; 103 | } 104 | 105 | /** 106 | * Convert wstETH to ETH 107 | */ 108 | function _unwrapETH( 109 | uint256 _totalInputValue, 110 | AztecTypes.AztecAsset calldata _outputAsset, 111 | uint256 _interactionNonce 112 | ) private returns (uint256 outputValue) { 113 | if (_outputAsset.assetType != AztecTypes.AztecAssetType.ETH) { 114 | revert ErrorLib.InvalidOutputA(); 115 | } 116 | 117 | // Convert wstETH to stETH so we can exchange it on curve 118 | uint256 stETH = WRAPPED_STETH.unwrap(_totalInputValue); 119 | 120 | // Exchange stETH to ETH via curve 121 | uint256 dy = CURVE_POOL.exchange(CURVE_STETH_INDEX, CURVE_ETH_INDEX, stETH, 0); 122 | 123 | outputValue = address(this).balance; 124 | if (outputValue < dy) { 125 | revert InvalidUnwrapReturnValue(); 126 | } 127 | 128 | // Send ETH to rollup processor 129 | IRollupProcessor(ROLLUP_PROCESSOR).receiveEthFromBridge{value: outputValue}(_interactionNonce); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/deployment/angle/AngleSLPDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {AngleSLPBridge} from "../../bridges/angle/AngleSLPBridge.sol"; 7 | 8 | contract AngleSLPDeployment is BaseDeployment { 9 | function deploy() public returns (address payable) { 10 | emit log("Deploying Angle SLP bridge"); 11 | 12 | vm.broadcast(); 13 | AngleSLPBridge bridge = new AngleSLPBridge(ROLLUP_PROCESSOR); 14 | emit log_named_address("Angle SLP bridge deployed to", address(bridge)); 15 | 16 | return payable(address(bridge)); 17 | } 18 | 19 | function deployAndList() public returns (address) { 20 | address payable bridge = deploy(); 21 | uint256 addressId = listBridge(bridge, 250000); 22 | emit log_named_uint("Angle SLP deposit bridge address id", addressId); 23 | addressId = listBridge(bridge, 1500000); 24 | emit log_named_uint("Angle SLP withdraw bridge address id", addressId); 25 | 26 | // Listing just the san tokens whose underlying are currently listed 27 | listAsset(AngleSLPBridge(bridge).SANDAI(), 55000); 28 | listAsset(AngleSLPBridge(bridge).SANWETH(), 55000); 29 | 30 | return bridge; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/deployment/curve/CurveDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {CurveStEthBridge} from "../../bridges/curve/CurveStEthBridge.sol"; 7 | import {ILido} from "../../interfaces/lido/ILido.sol"; 8 | import {IWstETH} from "../../interfaces/lido/IWstETH.sol"; 9 | 10 | contract CurveDeployment is BaseDeployment { 11 | function fundWithDust(address _bridge) public { 12 | CurveStEthBridge bridge = CurveStEthBridge(payable(_bridge)); 13 | 14 | ILido steth = bridge.LIDO(); 15 | IWstETH wstETH = bridge.WRAPPED_STETH(); 16 | 17 | vm.label(address(steth), "STETH"); 18 | vm.label(address(wstETH), "WSTETH"); 19 | 20 | vm.startBroadcast(); 21 | steth.submit{value: 1000}(address(0)); 22 | steth.transfer(address(bridge), 10); 23 | 24 | steth.approve(address(wstETH), 1000); 25 | wstETH.wrap(50); 26 | wstETH.transfer(address(bridge), 10); 27 | wstETH.transfer(ROLLUP_PROCESSOR, 10); 28 | 29 | vm.stopBroadcast(); 30 | 31 | assertGt(steth.balanceOf(address(bridge)), 0, "no steth"); 32 | assertGt(wstETH.balanceOf(address(bridge)), 0, "no wsteth"); 33 | } 34 | 35 | function deploy() public returns (address, address) { 36 | emit log("Deploying curve steth bridge"); 37 | 38 | vm.broadcast(); 39 | CurveStEthBridge bridge = new CurveStEthBridge(ROLLUP_PROCESSOR); 40 | 41 | emit log_named_address("Curve bridge deployed to", address(bridge)); 42 | 43 | assertEq(bridge.WRAPPED_STETH().allowance(address(bridge), ROLLUP_PROCESSOR), type(uint256).max); 44 | assertEq(bridge.LIDO().allowance(address(bridge), address(bridge.WRAPPED_STETH())), type(uint256).max); 45 | assertEq(bridge.LIDO().allowance(address(bridge), address(bridge.CURVE_POOL())), type(uint256).max); 46 | 47 | return (address(bridge), address(bridge.WRAPPED_STETH())); 48 | } 49 | 50 | function deployAndFund() public returns (address, address) { 51 | (address bridge, address wstEth) = deploy(); 52 | fundWithDust(bridge); 53 | return (bridge, wstEth); 54 | } 55 | 56 | function deployAndList() public returns (address, address) { 57 | (address bridge, address wstEth) = deployAndFund(); 58 | 59 | uint256 addressId = listBridge(bridge, 250000); 60 | emit log_named_uint("Curve bridge address id", addressId); 61 | 62 | listAsset(wstEth, 100000); 63 | 64 | return (bridge, wstEth); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/deployment/curve/CurveStethLpDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 7 | import {CurveStEthBridge} from "../../bridges/curve/CurveStEthBridge.sol"; 8 | import {ILido} from "../../interfaces/lido/ILido.sol"; 9 | import {IWstETH} from "../../interfaces/lido/IWstETH.sol"; 10 | import {Deployer} from "../../bridges/curve/Deployer.sol"; 11 | import {ICurvePool} from "../../interfaces/curve/ICurvePool.sol"; 12 | 13 | /* solhint-disable */ 14 | 15 | interface ICurveStEthLpBridge { 16 | function CURVE_POOL() external view returns (address); 17 | 18 | function LP_TOKEN() external view returns (address); 19 | } 20 | 21 | interface ICurveStEthPool { 22 | function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) external payable returns (uint256); 23 | } 24 | 25 | /* solhint-enable */ 26 | 27 | contract CurveStethLpDeployment is BaseDeployment { 28 | ILido internal constant STETH = ILido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); 29 | IWstETH internal constant WSTETH = IWstETH(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0); 30 | address internal constant CURVE_POOL = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022; 31 | 32 | function fundWithDust(address _bridge) public { 33 | ICurveStEthLpBridge bridge = ICurveStEthLpBridge(_bridge); 34 | IERC20 lpToken = IERC20(bridge.LP_TOKEN()); 35 | 36 | vm.label(address(STETH), "STETH"); 37 | vm.label(address(WSTETH), "WSTETH"); 38 | 39 | uint256[2] memory amounts; 40 | amounts[0] = 1000; 41 | 42 | vm.startBroadcast(); 43 | STETH.submit{value: 1000}(address(0)); 44 | STETH.transfer(_bridge, 10); 45 | 46 | STETH.approve(address(WSTETH), 1000); 47 | WSTETH.wrap(50); 48 | WSTETH.transfer(_bridge, 10); 49 | WSTETH.transfer(ROLLUP_PROCESSOR, 10); 50 | 51 | ICurveStEthPool(CURVE_POOL).add_liquidity{value: amounts[0]}(amounts, 0); 52 | lpToken.transfer(ROLLUP_PROCESSOR, 10); 53 | lpToken.transfer(_bridge, 10); 54 | 55 | vm.stopBroadcast(); 56 | 57 | assertGt(STETH.balanceOf(_bridge), 0, "no steth"); 58 | assertGt(WSTETH.balanceOf(_bridge), 0, "no wsteth"); 59 | } 60 | 61 | function deploy() public returns (address) { 62 | emit log("Deploying curve steth lp bridge"); 63 | 64 | vm.broadcast(); 65 | Deployer deployer = new Deployer(); 66 | 67 | string[] memory cmds = new string[](2); 68 | cmds[0] = "vyper"; 69 | cmds[1] = "src/bridges/curve/CurveStEthLpBridge.vy"; 70 | bytes memory code = vm.ffi(cmds); 71 | 72 | bytes memory bytecode = abi.encodePacked(code, abi.encode(ROLLUP_PROCESSOR)); 73 | 74 | vm.broadcast(); 75 | address bridgeAddress = deployer.deploy(bytecode); 76 | ICurveStEthLpBridge bridge = ICurveStEthLpBridge(bridgeAddress); 77 | 78 | emit log_named_address("Curve LP bridge deployed to", address(bridge)); 79 | 80 | emit log_named_address("Lp token", bridge.LP_TOKEN()); 81 | 82 | assertEq(WSTETH.allowance(address(bridge), ROLLUP_PROCESSOR), type(uint256).max); 83 | assertEq(STETH.allowance(address(bridge), address(WSTETH)), type(uint256).max); 84 | assertEq(STETH.allowance(address(bridge), CURVE_POOL), type(uint256).max); 85 | assertEq(IERC20(bridge.LP_TOKEN()).allowance(address(bridge), ROLLUP_PROCESSOR), type(uint256).max); 86 | 87 | return bridgeAddress; 88 | } 89 | 90 | function deployAndFund() public returns (address) { 91 | address bridge = deploy(); 92 | fundWithDust(bridge); 93 | return bridge; 94 | } 95 | 96 | function deployAndList() public returns (address, address) { 97 | address bridge = deployAndFund(); 98 | ICurveStEthLpBridge bridge_ = ICurveStEthLpBridge(bridge); 99 | 100 | uint256 addressId = listBridge(bridge, 250000); 101 | emit log_named_uint("Curve bridge address id", addressId); 102 | 103 | listAsset(bridge_.LP_TOKEN(), 55000); 104 | 105 | return (bridge, bridge_.LP_TOKEN()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/deployment/dca/DCADeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {UniswapDCABridge} from "../../bridges/dca/UniswapDCABridge.sol"; 7 | import {IWETH} from "../../interfaces/IWETH.sol"; 8 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 9 | 10 | contract DCADeployment is BaseDeployment { 11 | uint256 internal constant TICK_SIZE = 1 days; 12 | uint256 internal constant FEE = 10; // 10 bps 13 | 14 | function deploy() public returns (address) { 15 | emit log("Deploying Uniswap DCA bridge"); 16 | 17 | vm.broadcast(); 18 | UniswapDCABridge bridge = new UniswapDCABridge(ROLLUP_PROCESSOR, TICK_SIZE, FEE); 19 | 20 | emit log_named_address("Uniswap DCA bridge deployed to", address(bridge)); 21 | 22 | assertEq(bridge.ASSET_A().allowance(address(bridge), ROLLUP_PROCESSOR), type(uint256).max); 23 | assertEq(bridge.ASSET_B().allowance(address(bridge), ROLLUP_PROCESSOR), type(uint256).max); 24 | 25 | return address(bridge); 26 | } 27 | 28 | function deployAndList() public returns (address) { 29 | address bridge = deploy(); 30 | 31 | uint256 addressId = listBridge(bridge, 400000); 32 | emit log_named_uint("Uniswap DCA bridge address id", addressId); 33 | 34 | return bridge; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/deployment/donation/DonationDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 7 | import {DonationBridge} from "../../bridges/donation/DonationBridge.sol"; 8 | 9 | contract DonationDeployment is BaseDeployment { 10 | function deploy() public returns (address) { 11 | emit log("Deploying Donation bridge"); 12 | 13 | vm.broadcast(); 14 | DonationBridge bridge = new DonationBridge(ROLLUP_PROCESSOR); 15 | emit log_named_address("Donation bridge deployed to", address(bridge)); 16 | 17 | return address(bridge); 18 | } 19 | 20 | function deployAndList() public { 21 | address bridge = deploy(); 22 | uint256 addressId = listBridge(bridge, 100000); 23 | emit log_named_uint("Donation bridge address id", addressId); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/deployment/element/ElementDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 6 | 7 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 8 | import {ElementBridge} from "../../bridges/element/ElementBridge.sol"; 9 | 10 | contract ElementDeployment is BaseDeployment { 11 | address internal constant TRANCHE_FACTORY = 0x62F161BF3692E4015BefB05A03a94A40f520d1c0; 12 | address internal constant ELEMENT_REGISTRY_ADDRESS = 0xc68e2BAb13a7A2344bb81badBeA626012C62C510; 13 | bytes32 internal constant TRANCHE_BYTECODE_HASH = 0xf481a073666136ab1f5e93b296e84df58092065256d0db23b2d22b62c68e978d; 14 | address internal constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; 15 | 16 | function deployAndList() public returns (address) { 17 | emit log("Deploying element bridge"); 18 | vm.broadcast(); 19 | ElementBridge bridge = new ElementBridge( 20 | ROLLUP_PROCESSOR, 21 | TRANCHE_FACTORY, 22 | TRANCHE_BYTECODE_HASH, 23 | BALANCER_VAULT, 24 | ELEMENT_REGISTRY_ADDRESS 25 | ); 26 | emit log_named_address("element bridge deployed to", address(bridge)); 27 | 28 | uint256 addressId = listBridge(address(bridge), 800000); 29 | emit log_named_uint("Curve bridge address id", addressId); 30 | 31 | return address(bridge); 32 | } 33 | 34 | function registerPool(address _bridge, address _pool, address _position, uint64 _expiry) public { 35 | if (_expiry < block.timestamp) { 36 | return; 37 | } 38 | 39 | string memory symbol = IERC20Metadata(_position).symbol(); 40 | string memory s = string(abi.encodePacked("Registering ", symbol, " pool with expiry at ")); 41 | 42 | emit log_named_uint(s, _expiry); 43 | 44 | vm.broadcast(); 45 | ElementBridge(_bridge).registerConvergentPoolAddress(_pool, _position, _expiry); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/deployment/erc4626/ERC4626Deployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 7 | import {ERC4626Bridge} from "../../bridges/erc4626/ERC4626Bridge.sol"; 8 | import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; 9 | 10 | contract ERC4626Deployment is BaseDeployment { 11 | function deploy() public returns (address) { 12 | emit log("Deploying ERC4626 bridge"); 13 | 14 | vm.broadcast(); 15 | ERC4626Bridge bridge = new ERC4626Bridge(ROLLUP_PROCESSOR); 16 | emit log_named_address("ERC4626 bridge deployed to", address(bridge)); 17 | 18 | return address(bridge); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/deployment/erc4626/ERC4626DustSetter.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 7 | import {ERC4626Bridge} from "../../bridges/erc4626/ERC4626Bridge.sol"; 8 | import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; 9 | 10 | contract ERC4626DustSetter is BaseDeployment { 11 | IERC4626 private constant VAULT = IERC4626(0x60897720AA966452e8706e74296B018990aEc527); // ERC4626-Wrapped Euler wstETH 12 | address private constant BRIDGE = 0x3578D6D5e1B4F07A48bb1c958CBfEc135bef7d98; 13 | 14 | function depositToVaultAndSendDustToBridge() public { 15 | address asset = VAULT.asset(); 16 | vm.startBroadcast(); 17 | IERC20(asset).approve(address(VAULT), type(uint256).max); 18 | VAULT.mint(1, BRIDGE); 19 | vm.stopBroadcast(); 20 | 21 | emit log_named_uint("Share balance of bridge", VAULT.balanceOf(BRIDGE)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/deployment/erc4626/ERC4626Lister.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 7 | import {ERC4626Bridge} from "../../bridges/erc4626/ERC4626Bridge.sol"; 8 | import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; 9 | import {IRollupProcessor} from "rollup-encoder/interfaces/IRollupProcessor.sol"; 10 | 11 | contract ERC4626Lister is BaseDeployment { 12 | function listVault(address _bridge, address _vault) public { 13 | ERC4626Bridge bridge = ERC4626Bridge(payable(_bridge)); 14 | 15 | IERC4626 vault = IERC4626(_vault); 16 | IERC20 asset = IERC20(vault.asset()); 17 | 18 | // Not checking `asset.allowance(address(bridge), ROLLUP_PROCESSOR)` because it could have been set before 19 | // when listing other vaults with the same asset 20 | if (vault.allowance(address(bridge), ROLLUP_PROCESSOR) == type(uint256).max) { 21 | return; 22 | } 23 | if (asset.allowance(address(bridge), address(vault)) == type(uint256).max) { 24 | return; 25 | } 26 | 27 | vm.broadcast(); 28 | bridge.listVault(address(vault)); 29 | 30 | emit log_named_string("Listed vault", vault.symbol()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/deployment/example/ExampleDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {ExampleBridge} from "../../bridges/example/ExampleBridge.sol"; 7 | 8 | contract ExampleDeployment is BaseDeployment { 9 | function deploy() public returns (address) { 10 | emit log("Deploying example bridge"); 11 | 12 | vm.broadcast(); 13 | ExampleBridge bridge = new ExampleBridge(ROLLUP_PROCESSOR); 14 | 15 | emit log_named_address("Example bridge deployed to", address(bridge)); 16 | 17 | return address(bridge); 18 | } 19 | 20 | function deployAndList() public { 21 | address bridge = deploy(); 22 | uint256 addressId = listBridge(bridge, 250000); 23 | emit log_named_uint("Example bridge address id", addressId); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/deployment/liquity/LiquityTroveDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {TroveBridge} from "../../bridges/liquity/TroveBridge.sol"; 7 | import {IHintHelpers} from "../../interfaces/liquity/IHintHelpers.sol"; 8 | import {ITroveManager} from "../../interfaces/liquity/ITroveManager.sol"; 9 | import {ISortedTroves} from "../../interfaces/liquity/ISortedTroves.sol"; 10 | 11 | contract LiquityTroveDeployment is BaseDeployment { 12 | IHintHelpers internal constant HINT_HELPERS = IHintHelpers(0xE84251b93D9524E0d2e621Ba7dc7cb3579F997C0); 13 | ITroveManager public constant TROVE_MANAGER = ITroveManager(0xA39739EF8b0231DbFA0DcdA07d7e29faAbCf4bb2); 14 | ISortedTroves internal constant SORTED_TROVES = ISortedTroves(0x8FdD3fbFEb32b28fb73555518f8b361bCeA741A6); 15 | 16 | uint64 internal constant MAX_FEE = 1e16; // Slippage protection: 1% 17 | // From LiquityMath.sol 18 | uint256 internal constant NICR_PRECISION = 1e20; 19 | 20 | function deploy(uint256 _initialCr) public returns (address) { 21 | emit log("Deploying trove bridge"); 22 | 23 | vm.broadcast(); 24 | TroveBridge bridge = new TroveBridge(ROLLUP_PROCESSOR, _initialCr); 25 | 26 | emit log_named_address("Trove bridge deployed to", address(bridge)); 27 | 28 | return address(bridge); 29 | } 30 | 31 | function deployAndList(uint256 _initialCr) public { 32 | address bridge = deploy(_initialCr); 33 | uint256 addressId = listBridge(bridge, 700_000); 34 | emit log_named_uint("Trove bridge address id", addressId); 35 | 36 | listAsset(TroveBridge(payable(bridge)).LUSD(), 55_000); 37 | listAsset(bridge, 55_000); 38 | 39 | openTrove(bridge); 40 | } 41 | 42 | function openTrove(address _bridge) public { 43 | TroveBridge bridge = TroveBridge(payable(_bridge)); 44 | 45 | // 2100 LUSD --> 1800 LUSD is minimum but we also need to cover borrowing fee + liquidation reserve 46 | uint256 amtToBorrow = 21e20; 47 | uint256 collateral = _computeRequiredCollateral(amtToBorrow, bridge.INITIAL_ICR()); 48 | 49 | emit log_named_uint("Collateral", collateral); 50 | 51 | uint256 nicr = (collateral * NICR_PRECISION) / amtToBorrow; 52 | 53 | // The following is Solidity implementation of https://github.com/liquity/dev#opening-a-trove 54 | uint256 numTrials = 15; 55 | uint256 randomSeed = 42; 56 | (address approxHint,,) = HINT_HELPERS.getApproxHint(nicr, numTrials, randomSeed); 57 | (address upperHint, address lowerHint) = SORTED_TROVES.findInsertPosition(nicr, approxHint, approxHint); 58 | 59 | // Open the trove 60 | vm.broadcast(); 61 | bridge.openTrove{value: collateral}(upperHint, lowerHint, MAX_FEE); 62 | 63 | uint256 status = TROVE_MANAGER.getTroveStatus(address(bridge)); 64 | emit log_named_uint("Trove status", status); 65 | assertEq(status, 1, "Incorrect trove status - opening the trove failed"); 66 | } 67 | 68 | function _computeRequiredCollateral(uint256 _amtToBorrow, uint256 _icr) internal returns (uint256) { 69 | uint256 price = TROVE_MANAGER.priceFeed().fetchPrice(); 70 | return (_amtToBorrow * _icr) / price; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/deployment/subsidy/SubsidyDeployment.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {Subsidy} from "../../aztec/Subsidy.sol"; 7 | 8 | contract SubsidyDeployment is BaseDeployment { 9 | function deploy() public returns (address) { 10 | emit log("Deploying Subsidy contract"); 11 | 12 | vm.broadcast(); 13 | Subsidy subsidy = new Subsidy(); 14 | emit log_named_address("Subsidy contract deployed to ", address(subsidy)); 15 | 16 | return address(subsidy); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/deployment/uniswap/UniswapDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 6 | import {UniswapBridge} from "../../bridges/uniswap/UniswapBridge.sol"; 7 | 8 | contract UniswapDeployment is BaseDeployment { 9 | address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; 10 | address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; 11 | 12 | function deploy() public returns (address) { 13 | emit log("Deploying uniswap bridge"); 14 | 15 | vm.broadcast(); 16 | UniswapBridge bridge = new UniswapBridge(ROLLUP_PROCESSOR); 17 | 18 | emit log_named_address("Uniswap bridge deployed to", address(bridge)); 19 | 20 | address[] memory tokens = new address[](2); 21 | tokens[0] = DAI; 22 | tokens[1] = WETH; 23 | 24 | vm.broadcast(); 25 | bridge.preApproveTokens(tokens, tokens); 26 | 27 | return address(bridge); 28 | } 29 | 30 | function deployAndList() public { 31 | address bridge = deploy(); 32 | uint256 addressId = listBridge(bridge, 500000); 33 | emit log_named_uint("Uniswap bridge address id", addressId); 34 | uint256 addressIdLarge = listBridge(bridge, 800000); 35 | emit log_named_uint("Uniswap large bridge address id", addressIdLarge); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/deployment/yearn/YearnDeployment.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {BaseDeployment} from "../base/BaseDeployment.s.sol"; 7 | import {YearnBridge} from "../../bridges/yearn/YearnBridge.sol"; 8 | import {IYearnRegistry} from "../../interfaces/yearn/IYearnRegistry.sol"; 9 | 10 | contract YearnDeployment is BaseDeployment { 11 | address public constant WETH = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); 12 | address public constant DAI = address(0x6B175474E89094C44Da98b954EedeAC495271d0F); 13 | 14 | IYearnRegistry public constant YEARN_REGISTRY = IYearnRegistry(0x50c1a2eA0a861A967D9d0FFE2AE4012c2E053804); 15 | 16 | function deploy() public returns (address) { 17 | emit log("Deploying yearn bridge"); 18 | 19 | vm.broadcast(); 20 | YearnBridge bridge = new YearnBridge(ROLLUP_PROCESSOR); 21 | 22 | emit log_named_address("Yearn bridge deployed to", address(bridge)); 23 | 24 | return address(bridge); 25 | } 26 | 27 | function approveAsset(address _bridge, address _asset) public returns (address) { 28 | YearnBridge bridge = YearnBridge(payable(_bridge)); 29 | address latestVault = YEARN_REGISTRY.latestVault(_asset); 30 | 31 | vm.broadcast(); 32 | bridge.preApprove(latestVault); 33 | 34 | return latestVault; 35 | } 36 | 37 | function deployAndList() public returns (address) { 38 | address bridge = deploy(); 39 | 40 | approveAsset(bridge, DAI); 41 | approveAsset(bridge, WETH); 42 | 43 | uint256 depositAddressId = listBridge(bridge, 200000); 44 | emit log_named_uint("Yearn deposit bridge address id", depositAddressId); 45 | 46 | uint256 withdrawAddressId = listBridge(bridge, 800000); 47 | emit log_named_uint("Yearn withdraw bridge address id", withdrawAddressId); 48 | 49 | listAsset(YEARN_REGISTRY.latestVault(DAI), 55000); 50 | listAsset(YEARN_REGISTRY.latestVault(WETH), 55000); 51 | 52 | return bridge; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/gas/base/GasBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 6 | 7 | contract GasBase { 8 | bytes4 private constant DEFI_BRIDGE_PROXY_CONVERT_SELECTOR = 0x4bd947a8; 9 | 10 | address public defiProxy; 11 | mapping(uint256 => uint256) public ethPayments; 12 | 13 | constructor(address _defiProxy) { 14 | defiProxy = _defiProxy; 15 | } 16 | 17 | receive() external payable {} 18 | 19 | fallback() external {} 20 | 21 | function receiveEthFromBridge(uint256 _interactionNonce) external payable { 22 | ethPayments[_interactionNonce] += msg.value; 23 | } 24 | 25 | function convert( 26 | address _bridgeAddress, 27 | AztecTypes.AztecAsset memory _inputAssetA, 28 | AztecTypes.AztecAsset memory _inputAssetB, 29 | AztecTypes.AztecAsset memory _outputAssetA, 30 | AztecTypes.AztecAsset memory _outputAssetB, 31 | uint256 _totalInputValue, 32 | uint256 _interactionNonce, 33 | uint256 _auxInputData, 34 | address _rollupBeneficiary, 35 | uint256 _gasLimit 36 | ) external { 37 | (bool success, bytes memory data) = address(defiProxy).delegatecall{gas: _gasLimit}( 38 | abi.encodeWithSelector( 39 | DEFI_BRIDGE_PROXY_CONVERT_SELECTOR, 40 | _bridgeAddress, 41 | _inputAssetA, 42 | _inputAssetB, 43 | _outputAssetA, 44 | _outputAssetB, 45 | _totalInputValue, 46 | _interactionNonce, 47 | _auxInputData, 48 | _getPaymentsSlot(), 49 | _rollupBeneficiary 50 | ) 51 | ); 52 | 53 | if (!success) { 54 | if (data.length == 0) revert("Revert without error message --> probably out of gas"); 55 | assembly { 56 | revert(add(32, data), mload(data)) 57 | } 58 | } 59 | } 60 | 61 | function getSupportedBridgesLength() external view returns (uint256) { 62 | return 0; 63 | } 64 | 65 | function getSupportedAssetsLength() external view returns (uint256) { 66 | return 0; 67 | } 68 | 69 | function _getPaymentsSlot() private returns (uint256 paymentSlot) { 70 | assembly { 71 | paymentSlot := ethPayments.slot 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/gas/curve/CurveGas.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {CurveStEthBridge} from "../../bridges/curve/CurveStEthBridge.sol"; 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; 9 | 10 | import {CurveDeployment} from "../../deployment/curve/CurveDeployment.s.sol"; 11 | import {GasBase} from "../base/GasBase.sol"; 12 | 13 | interface IRead { 14 | function defiBridgeProxy() external view returns (address); 15 | } 16 | 17 | contract CurveMeasure is CurveDeployment { 18 | GasBase internal gasBase; 19 | CurveStEthBridge internal bridge; 20 | 21 | function measure() public { 22 | address defiProxy = IRead(ROLLUP_PROCESSOR).defiBridgeProxy(); 23 | vm.label(defiProxy, "DefiProxy"); 24 | 25 | vm.broadcast(); 26 | gasBase = new GasBase(defiProxy); 27 | 28 | address temp = ROLLUP_PROCESSOR; 29 | ROLLUP_PROCESSOR = address(gasBase); 30 | (address bridge, address wstEth) = deployAndList(); 31 | ROLLUP_PROCESSOR = temp; 32 | 33 | AztecTypes.AztecAsset memory empty; 34 | AztecTypes.AztecAsset memory eth = 35 | AztecTypes.AztecAsset({id: 0, erc20Address: address(0), assetType: AztecTypes.AztecAssetType.ETH}); 36 | AztecTypes.AztecAsset memory wstEthAsset = 37 | AztecTypes.AztecAsset({id: 1, erc20Address: wstEth, assetType: AztecTypes.AztecAssetType.ERC20}); 38 | 39 | vm.broadcast(); 40 | address(gasBase).call{value: 2 ether}(""); 41 | emit log_named_uint("Balance of ", address(gasBase).balance); 42 | 43 | // Deposit 44 | { 45 | vm.broadcast(); 46 | gasBase.convert(bridge, eth, empty, wstEthAsset, empty, 1 ether, 0, 0, address(this), 250000); 47 | } 48 | 49 | // Withdraw 50 | { 51 | emit log_named_uint("bal", IERC20(wstEthAsset.erc20Address).balanceOf(address(gasBase))); 52 | 53 | vm.broadcast(); 54 | gasBase.convert(bridge, wstEthAsset, empty, eth, empty, 0.1 ether, 1, 1, address(this), 250000); 55 | emit log_named_uint("bal", IERC20(wstEthAsset.erc20Address).balanceOf(address(gasBase))); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/gas/curve/CurveLpGas.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {CurveStEthBridge} from "../../bridges/curve/CurveStEthBridge.sol"; 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; 9 | 10 | import {CurveStethLpDeployment} from "../../deployment/curve/CurveStethLpDeployment.s.sol"; 11 | import {GasBase} from "../base/GasBase.sol"; 12 | 13 | interface IRead { 14 | function defiBridgeProxy() external view returns (address); 15 | } 16 | 17 | contract CurveLpMeasure is CurveStethLpDeployment { 18 | GasBase internal gasBase; 19 | CurveStEthBridge internal bridge; 20 | 21 | function measure() public { 22 | address defiProxy = IRead(ROLLUP_PROCESSOR).defiBridgeProxy(); 23 | vm.label(defiProxy, "DefiProxy"); 24 | 25 | vm.broadcast(); 26 | gasBase = new GasBase(defiProxy); 27 | 28 | address temp = ROLLUP_PROCESSOR; 29 | ROLLUP_PROCESSOR = address(gasBase); 30 | (address bridge, address lpToken) = deployAndList(); 31 | ROLLUP_PROCESSOR = temp; 32 | 33 | AztecTypes.AztecAsset memory empty; 34 | AztecTypes.AztecAsset memory eth = 35 | AztecTypes.AztecAsset({id: 0, erc20Address: address(0), assetType: AztecTypes.AztecAssetType.ETH}); 36 | AztecTypes.AztecAsset memory wstEth = 37 | AztecTypes.AztecAsset({id: 0, erc20Address: address(WSTETH), assetType: AztecTypes.AztecAssetType.ERC20}); 38 | AztecTypes.AztecAsset memory lpAsset = 39 | AztecTypes.AztecAsset({id: 1, erc20Address: lpToken, assetType: AztecTypes.AztecAssetType.ERC20}); 40 | 41 | // Fund with WSTETH 42 | vm.startBroadcast(); 43 | STETH.submit{value: 1 ether}(address(0)); 44 | STETH.approve(address(WSTETH), 1 ether); 45 | WSTETH.wrap(1 ether); 46 | WSTETH.transfer(address(gasBase), 0.6 ether); 47 | vm.stopBroadcast(); 48 | 49 | vm.broadcast(); 50 | address(gasBase).call{value: 2 ether}(""); 51 | 52 | // add liquidity eth 53 | { 54 | vm.broadcast(); 55 | gasBase.convert(bridge, eth, empty, lpAsset, empty, 1 ether, 0, 0, address(this), 250000); 56 | } 57 | 58 | // add liquidity wsteth 59 | { 60 | vm.broadcast(); 61 | gasBase.convert(bridge, wstEth, empty, lpAsset, empty, 0.5 ether, 0, 0, address(this), 250000); 62 | } 63 | 64 | // Remove liquidity 65 | { 66 | vm.broadcast(); 67 | gasBase.convert(bridge, lpAsset, empty, eth, wstEth, 0.5 ether, 0, 0, address(this), 250000); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/gas/dca/DCAGas.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {UniswapDCABridge} from "../../bridges/dca/UniswapDCABridge.sol"; 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; 9 | 10 | import {DCADeployment} from "../../deployment/dca/DCADeployment.s.sol"; 11 | import {GasBase} from "../base/GasBase.sol"; 12 | 13 | interface IRead { 14 | function defiBridgeProxy() external view returns (address); 15 | } 16 | 17 | contract DCAMeasure is DCADeployment { 18 | GasBase internal gasBase; 19 | UniswapDCABridge internal bridge; 20 | 21 | function measure() public { 22 | address defiProxy = IRead(ROLLUP_PROCESSOR).defiBridgeProxy(); 23 | vm.label(defiProxy, "DefiProxy"); 24 | 25 | vm.broadcast(); 26 | gasBase = new GasBase(defiProxy); 27 | 28 | address temp = ROLLUP_PROCESSOR; 29 | ROLLUP_PROCESSOR = address(gasBase); 30 | address bridge = deployAndList(); 31 | ROLLUP_PROCESSOR = temp; 32 | 33 | AztecTypes.AztecAsset memory empty; 34 | AztecTypes.AztecAsset memory eth = 35 | AztecTypes.AztecAsset({id: 0, erc20Address: address(0), assetType: AztecTypes.AztecAssetType.ETH}); 36 | AztecTypes.AztecAsset memory daiAsset = AztecTypes.AztecAsset({ 37 | id: 1, 38 | erc20Address: 0x6B175474E89094C44Da98b954EedeAC495271d0F, 39 | assetType: AztecTypes.AztecAssetType.ERC20 40 | }); 41 | 42 | vm.broadcast(); 43 | address(gasBase).call{value: 2 ether}(""); 44 | emit log_named_uint("Balance of ", address(gasBase).balance); 45 | 46 | // Create DCA for 7 days 47 | { 48 | vm.broadcast(); 49 | gasBase.convert(bridge, eth, empty, daiAsset, empty, 1 ether, 0, 7, address(this), 400000); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/gas/liquity/TroveBridgeGas.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {TroveBridge} from "../../bridges/liquity/TroveBridge.sol"; 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; 9 | 10 | import {LiquityTroveDeployment, BaseDeployment} from "../../deployment/liquity/LiquityTroveDeployment.s.sol"; 11 | import {GasBase} from "../base/GasBase.sol"; 12 | 13 | interface IRead { 14 | function defiBridgeProxy() external view returns (address); 15 | } 16 | 17 | contract TroveBridgeMeasure is LiquityTroveDeployment { 18 | ISubsidy private constant SUBSIDY = ISubsidy(0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA); 19 | address private constant BENEFICIARY = address(uint160(uint256(keccak256(abi.encodePacked("_BENEFICIARY"))))); 20 | 21 | GasBase internal gasBase; 22 | TroveBridge internal bridge; 23 | 24 | AztecTypes.AztecAsset internal emptyAsset; 25 | AztecTypes.AztecAsset internal ethAsset; 26 | AztecTypes.AztecAsset internal lusdAsset; 27 | AztecTypes.AztecAsset internal tbAsset; // Accounting token 28 | 29 | function setUp() public override(BaseDeployment) { 30 | super.setUp(); 31 | 32 | address defiProxy = IRead(ROLLUP_PROCESSOR).defiBridgeProxy(); 33 | vm.label(defiProxy, "DefiProxy"); 34 | 35 | vm.broadcast(); 36 | gasBase = new GasBase(defiProxy); 37 | 38 | address temp = ROLLUP_PROCESSOR; 39 | ROLLUP_PROCESSOR = address(gasBase); 40 | bridge = TroveBridge(payable(deploy(400))); 41 | ROLLUP_PROCESSOR = temp; 42 | 43 | ethAsset = AztecTypes.AztecAsset({id: 0, erc20Address: address(0), assetType: AztecTypes.AztecAssetType.ETH}); 44 | lusdAsset = AztecTypes.AztecAsset({ 45 | id: 1, 46 | erc20Address: 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0, 47 | assetType: AztecTypes.AztecAssetType.ERC20 48 | }); 49 | tbAsset = 50 | AztecTypes.AztecAsset({id: 2, erc20Address: address(bridge), assetType: AztecTypes.AztecAssetType.ERC20}); 51 | 52 | vm.label(lusdAsset.erc20Address, "LUSD"); 53 | vm.label(tbAsset.erc20Address, "TB"); 54 | 55 | // Fund subsidy 56 | vm.startBroadcast(); 57 | SUBSIDY.subsidize{value: 1e17}(address(bridge), 0, 500); 58 | SUBSIDY.registerBeneficiary(BENEFICIARY); 59 | SUBSIDY.subsidize{value: 1e17}(address(bridge), 1, 300); 60 | SUBSIDY.registerBeneficiary(BENEFICIARY); 61 | vm.stopBroadcast(); 62 | 63 | // Warp time to increase subsidy 64 | vm.warp(block.timestamp + 10 days); 65 | } 66 | 67 | function measureETH() public { 68 | openTrove(address(bridge)); 69 | vm.broadcast(); 70 | address(gasBase).call{value: 2 ether}(""); 71 | emit log_named_uint("ETH balance of gasBase", address(gasBase).balance); 72 | 73 | // Borrow 74 | { 75 | vm.broadcast(); 76 | gasBase.convert( 77 | address(bridge), ethAsset, emptyAsset, tbAsset, lusdAsset, 1 ether, 0, MAX_FEE, BENEFICIARY, 630000 78 | ); 79 | } 80 | 81 | uint256 claimableSubsidyAfterDeposit = SUBSIDY.claimableAmount(BENEFICIARY); 82 | assertGt(claimableSubsidyAfterDeposit, 0, "Subsidy was not claimed during deposit"); 83 | emit log_named_uint("Claimable subsidy after deposit", claimableSubsidyAfterDeposit); 84 | 85 | // Repay 86 | { 87 | uint256 lusdBalance = IERC20(lusdAsset.erc20Address).balanceOf(address(gasBase)); 88 | uint256 tbBalance = IERC20(tbAsset.erc20Address).balanceOf(address(gasBase)); 89 | 90 | emit log_named_uint("LUSD balance", lusdBalance); 91 | emit log_named_uint("TB balance", tbBalance); 92 | 93 | vm.broadcast(); 94 | gasBase.convert( 95 | address(bridge), tbAsset, lusdAsset, ethAsset, lusdAsset, lusdBalance / 2, 0, 0, BENEFICIARY, 480000 96 | ); 97 | } 98 | 99 | uint256 claimableSubsidyAfterRepayment = SUBSIDY.claimableAmount(BENEFICIARY); 100 | assertGt( 101 | claimableSubsidyAfterRepayment, claimableSubsidyAfterDeposit, "Subsidy was not claimed during repayment" 102 | ); 103 | emit log_named_uint("Claimable subsidy after repayment", claimableSubsidyAfterRepayment); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/gas/uniswap/UniswapGas.s.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {UniswapBridge} from "../../bridges/uniswap/UniswapBridge.sol"; 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {ISubsidy} from "../../aztec/interfaces/ISubsidy.sol"; 9 | import {IWETH} from "../../interfaces/IWETH.sol"; 10 | 11 | import {UniswapDeployment, BaseDeployment} from "../../deployment/uniswap/UniswapDeployment.s.sol"; 12 | import {GasBase} from "../base/GasBase.sol"; 13 | 14 | interface IRead { 15 | function defiBridgeProxy() external view returns (address); 16 | } 17 | 18 | contract UniswapMeasure is UniswapDeployment { 19 | ISubsidy private constant SUBSIDY = ISubsidy(0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA); 20 | address private constant BENEFICIARY = address(uint160(uint256(keccak256(abi.encodePacked("_BENEFICIARY"))))); 21 | 22 | address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; 23 | address public constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; 24 | address public constant FRAX = 0x853d955aCEf822Db058eb8505911ED77F175b99e; 25 | 26 | GasBase internal gasBase; 27 | UniswapBridge internal bridge; 28 | 29 | AztecTypes.AztecAsset internal emptyAsset; 30 | AztecTypes.AztecAsset internal ethAsset; 31 | AztecTypes.AztecAsset internal wethAsset; 32 | AztecTypes.AztecAsset internal daiAsset; 33 | 34 | UniswapBridge.SplitPath internal emptySplitPath; 35 | 36 | function setUp() public override(BaseDeployment) { 37 | super.setUp(); 38 | 39 | address defiProxy = IRead(ROLLUP_PROCESSOR).defiBridgeProxy(); 40 | vm.label(defiProxy, "DefiProxy"); 41 | 42 | vm.broadcast(); 43 | gasBase = new GasBase(defiProxy); 44 | 45 | address temp = ROLLUP_PROCESSOR; 46 | ROLLUP_PROCESSOR = address(gasBase); 47 | bridge = UniswapBridge(payable(deploy())); 48 | ROLLUP_PROCESSOR = temp; 49 | 50 | ethAsset = AztecTypes.AztecAsset({id: 0, erc20Address: address(0), assetType: AztecTypes.AztecAssetType.ETH}); 51 | wethAsset = 52 | AztecTypes.AztecAsset({id: 2, erc20Address: address(WETH), assetType: AztecTypes.AztecAssetType.ERC20}); 53 | daiAsset = AztecTypes.AztecAsset({ 54 | id: 1, 55 | erc20Address: 0x6B175474E89094C44Da98b954EedeAC495271d0F, 56 | assetType: AztecTypes.AztecAssetType.ERC20 57 | }); 58 | 59 | // List vaults and fund subsidy 60 | vm.startBroadcast(); 61 | bridge.registerSubsidyCriteria(ethAsset.erc20Address, daiAsset.erc20Address); 62 | bridge.registerSubsidyCriteria(daiAsset.erc20Address, ethAsset.erc20Address); 63 | SUBSIDY.subsidize{value: 1e17}( 64 | address(bridge), bridge.computeCriteria(ethAsset, emptyAsset, daiAsset, emptyAsset, 0), 500 65 | ); 66 | SUBSIDY.subsidize{value: 1e17}( 67 | address(bridge), bridge.computeCriteria(daiAsset, emptyAsset, ethAsset, emptyAsset, 0), 500 68 | ); 69 | SUBSIDY.registerBeneficiary(BENEFICIARY); 70 | vm.stopBroadcast(); 71 | 72 | // Warp time to increase subsidy 73 | vm.warp(block.timestamp + 10 days); 74 | } 75 | 76 | function measure1SplitPathSwap() public { 77 | uint64 path = bridge.encodePath( 78 | 1 ether, 1e20, WETH, UniswapBridge.SplitPath(100, 500, USDC, 100, address(0), 100), emptySplitPath 79 | ); 80 | 81 | vm.broadcast(); 82 | address(gasBase).call{value: 2 ether}(""); 83 | emit log_named_uint("ETH balance of gasBase", address(gasBase).balance); 84 | 85 | { 86 | vm.broadcast(); 87 | gasBase.convert( 88 | address(bridge), ethAsset, emptyAsset, daiAsset, emptyAsset, 1 ether, 0, path, BENEFICIARY, 300000 89 | ); 90 | } 91 | 92 | uint256 claimableSubsidyAfterDeposit = SUBSIDY.claimableAmount(BENEFICIARY); 93 | assertGt(claimableSubsidyAfterDeposit, 0, "Subsidy was not claimed during deposit"); 94 | emit log_named_uint("Claimable subsidy after deposit", claimableSubsidyAfterDeposit); 95 | } 96 | 97 | function measureMaxComplexPath() public { 98 | uint64 path = bridge.encodePath( 99 | 1 ether, 100 | 1e20, 101 | WETH, 102 | UniswapBridge.SplitPath(50, 500, USDC, 100, FRAX, 500), 103 | UniswapBridge.SplitPath(50, 3000, USDT, 100, USDC, 500) 104 | ); 105 | 106 | vm.broadcast(); 107 | address(gasBase).call{value: 2 ether}(""); 108 | emit log_named_uint("ETH balance of gasBase", address(gasBase).balance); 109 | 110 | { 111 | vm.broadcast(); 112 | gasBase.convert( 113 | address(bridge), ethAsset, emptyAsset, daiAsset, emptyAsset, 1 ether, 0, path, BENEFICIARY, 660000 114 | ); 115 | } 116 | 117 | uint256 claimableSubsidyAfterDeposit = SUBSIDY.claimableAmount(BENEFICIARY); 118 | assertGt(claimableSubsidyAfterDeposit, 0, "Subsidy was not claimed during deposit"); 119 | emit log_named_uint("Claimable subsidy after deposit", claimableSubsidyAfterDeposit); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/interfaces/IWETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | interface IWETH is IERC20 { 8 | function deposit() external payable; 9 | 10 | function withdraw(uint256 amount) external; 11 | } 12 | -------------------------------------------------------------------------------- /src/interfaces/angle/IPoolManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | interface IPoolManager { 8 | struct StrategyParams { 9 | // Timestamp of last report made by this strategy 10 | // It is also used to check if a strategy has been initialized 11 | uint256 lastReport; 12 | // Total amount the strategy is expected to have 13 | uint256 totalStrategyDebt; 14 | // The share of the total assets in the `PoolManager` contract that the `strategy` can access to. 15 | uint256 debtRatio; 16 | } 17 | 18 | function strategies(address _strategy) external view returns (StrategyParams memory); 19 | 20 | function strategyList(uint256) external view returns (address); 21 | } 22 | 23 | interface IStrategy { 24 | function harvest() external; 25 | } 26 | -------------------------------------------------------------------------------- /src/interfaces/angle/IStableMaster.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | interface IStableMaster { 8 | struct MintBurnData { 9 | uint64[] xFeeMint; 10 | uint64[] yFeeMint; 11 | uint64[] xFeeBurn; 12 | uint64[] yFeeBurn; 13 | uint64 targetHAHedge; 14 | uint64 bonusMalusMint; 15 | uint64 bonusMalusBurn; 16 | uint256 capOnStableMinted; 17 | } 18 | 19 | struct SLPData { 20 | uint256 lastBlockUpdated; 21 | uint256 lockedInterests; 22 | uint256 maxInterestsDistributed; 23 | uint256 feesAside; 24 | uint64 slippageFee; 25 | uint64 feesForSLPs; 26 | uint64 slippage; 27 | uint64 interestsForSLPs; 28 | } 29 | 30 | function deposit(uint256 amount, address user, address poolManager) external; 31 | 32 | function withdraw(uint256 amount, address burner, address dest, address poolManager) external; 33 | 34 | function agToken() external returns (address); 35 | 36 | function collateralMap(address poolManager) 37 | external 38 | view 39 | returns ( 40 | IERC20 token, 41 | address sanToken, 42 | address perpetualManager, 43 | address oracle, 44 | uint256 stocksUsers, 45 | uint256 sanRate, 46 | uint256 collatBase, 47 | SLPData memory slpData, 48 | MintBurnData memory feeData 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/interfaces/chainlink/IChainlinkOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | interface IChainlinkOracle { 6 | function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80); 7 | } 8 | -------------------------------------------------------------------------------- /src/interfaces/compound/ICERC20.sol: -------------------------------------------------------------------------------- 1 | // Note: only used in client 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ICERC20 is IERC20 { 7 | function supplyRatePerBlock() external view returns (uint256); 8 | 9 | function accrueInterest() external; 10 | 11 | function balanceOfUnderlying(address) external view returns (uint256); 12 | 13 | function totalBorrows() external view returns (uint256); 14 | 15 | function exchangeRateStored() external view returns (uint256); 16 | 17 | function exchangeRateCurrent() external returns (uint256); 18 | 19 | function mint(uint256) external returns (uint256); 20 | 21 | function redeem(uint256) external returns (uint256); 22 | 23 | function redeemUnderlying(uint256) external returns (uint256); 24 | 25 | function underlying() external returns (address); 26 | } 27 | -------------------------------------------------------------------------------- /src/interfaces/compound/ICompoundERC4626.sol: -------------------------------------------------------------------------------- 1 | // Note: only used in client 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ICompoundERC4626 { 7 | function cToken() external view virtual returns (address); 8 | } 9 | -------------------------------------------------------------------------------- /src/interfaces/curve/ICurvePool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | pragma solidity >=0.8.4; 3 | 4 | interface ICurvePool { 5 | function coins(uint256) external view returns (address); 6 | 7 | function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256); 8 | 9 | function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external payable returns (uint256); 10 | } 11 | -------------------------------------------------------------------------------- /src/interfaces/element/IDeploymentValidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | interface IDeploymentValidator { 5 | function validateWPAddress(address wrappedPosition) external; 6 | 7 | function validatePoolAddress(address pool) external; 8 | 9 | function validateAddresses(address wrappedPosition, address pool) external; 10 | 11 | function checkWPValidation(address wrappedPosition) external view returns (bool); 12 | 13 | function checkPoolValidation(address pool) external view returns (bool); 14 | 15 | function checkPairValidation(address wrappedPosition, address pool) external view returns (bool); 16 | } 17 | -------------------------------------------------------------------------------- /src/interfaces/element/IPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.7.5; 3 | pragma abicoder v2; 4 | 5 | import {IVault} from "./IVault.sol"; 6 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 7 | import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 8 | 9 | interface IPool is IERC20, IERC20Permit { 10 | /// @dev Returns the poolId for this pool 11 | /// @return The poolId for this pool 12 | function getPoolId() external view returns (bytes32); 13 | 14 | function underlying() external view returns (IERC20); 15 | 16 | function expiration() external view returns (uint256); 17 | 18 | function getVault() external view returns (IVault); 19 | } 20 | -------------------------------------------------------------------------------- /src/interfaces/element/ITranche.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.6.10; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 6 | 7 | interface ITranche is IERC20, IERC20Permit { 8 | function deposit(uint256 _shares, address destination) external returns (uint256, uint256); 9 | 10 | function prefundedDeposit(address _destination) external returns (uint256, uint256); 11 | 12 | function withdrawPrincipal(uint256 _amount, address _destination) external returns (uint256); 13 | 14 | function withdrawInterest(uint256 _amount, address _destination) external returns (uint256); 15 | 16 | function interestSupply() external view returns (uint128); 17 | 18 | function position() external view returns (IERC20); 19 | 20 | function underlying() external view returns (IERC20); 21 | 22 | function speedbump() external view returns (uint256); 23 | 24 | function unlockTimestamp() external view returns (uint256); 25 | 26 | function hitSpeedbump() external; 27 | } 28 | -------------------------------------------------------------------------------- /src/interfaces/element/IVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface IAsset { 7 | // solhint-disable-previous-line no-empty-blocks 8 | } 9 | 10 | enum PoolSpecialization { 11 | GENERAL, 12 | MINIMAL_SWAP_INFO, 13 | TWO_TOKEN 14 | } 15 | 16 | interface IVault { 17 | enum SwapKind { 18 | GIVEN_IN, 19 | GIVEN_OUT 20 | } 21 | 22 | /** 23 | * @dev Performs a swap with a single Pool. 24 | * 25 | * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens 26 | * taken from the Pool, which must be greater than or equal to `limit`. 27 | * 28 | * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens 29 | * sent to the Pool, which must be less than or equal to `limit`. 30 | * 31 | * Internal Balance usage and the recipient are determined by the `funds` struct. 32 | * 33 | * Emits a `Swap` event. 34 | */ 35 | function swap(SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline) 36 | external 37 | payable 38 | returns (uint256); 39 | 40 | /** 41 | * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on 42 | * the `kind` value. 43 | * 44 | * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address). 45 | * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault. 46 | * 47 | * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be 48 | * used to extend swap behavior. 49 | */ 50 | struct SingleSwap { 51 | bytes32 poolId; 52 | SwapKind kind; 53 | IAsset assetIn; 54 | IAsset assetOut; 55 | uint256 amount; 56 | bytes userData; 57 | } 58 | 59 | /** 60 | * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the 61 | * `recipient` account. 62 | * 63 | * If the caller is not `sender`, it must be an authorized relayer for them. 64 | * 65 | * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20 66 | * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender` 67 | * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of 68 | * `joinPool`. 69 | * 70 | * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of 71 | * transferred. This matches the behavior of `exitPool`. 72 | * 73 | * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a 74 | * revert. 75 | */ 76 | struct FundManagement { 77 | address sender; 78 | bool fromInternalBalance; 79 | address payable recipient; 80 | bool toInternalBalance; 81 | } 82 | 83 | // will revert if poolId is not a registered pool 84 | function getPool(bytes32 poolId) external view returns (address, PoolSpecialization); 85 | 86 | /** 87 | * @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be 88 | * simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result. 89 | * 90 | * Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH) 91 | * the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it 92 | * receives are the same that an equivalent `batchSwap` call would receive. 93 | * 94 | * Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct. 95 | * This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens, 96 | * approve them for the Vault, or even know a user's address. 97 | * 98 | * Note that this function is not 'view' (due to implementation details): the client code must explicitly execute 99 | * eth_call instead of eth_sendTransaction. 100 | */ 101 | 102 | struct BatchSwapStep { 103 | bytes32 poolId; 104 | uint256 assetInIndex; 105 | uint256 assetOutIndex; 106 | uint256 amount; 107 | bytes userData; 108 | } 109 | 110 | function queryBatchSwap( 111 | SwapKind kind, 112 | BatchSwapStep[] memory swaps, 113 | IAsset[] memory assets, 114 | FundManagement memory funds 115 | ) external view returns (int256[] memory assetDeltas); 116 | 117 | /** 118 | * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of 119 | * the tokens' `balances` changed. 120 | * 121 | * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all 122 | * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order. 123 | * 124 | * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same 125 | * order as passed to `registerTokens`. 126 | * 127 | * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are 128 | * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo` 129 | * instead. 130 | */ 131 | function getPoolTokens(bytes32 poolId) 132 | external 133 | view 134 | returns (IERC20[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); 135 | } 136 | -------------------------------------------------------------------------------- /src/interfaces/element/IWrappedPosition.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol"; 6 | 7 | interface IWrappedPosition is IERC20, IERC20Permit { 8 | function token() external view returns (IERC20); 9 | 10 | function vault() external view returns (address); 11 | 12 | function balanceOfUnderlying(address who) external view returns (uint256); 13 | 14 | function getSharesToUnderlying(uint256 shares) external view returns (uint256); 15 | 16 | function deposit(address sender, uint256 amount) external returns (uint256); 17 | 18 | function withdraw(address sender, uint256 _shares, uint256 _minUnderlying) external returns (uint256); 19 | 20 | function withdrawUnderlying(address _destination, uint256 _amount, uint256 _minUnderlying) 21 | external 22 | returns (uint256, uint256); 23 | 24 | function prefundedDeposit(address _destination) external returns (uint256, uint256, uint256); 25 | } 26 | -------------------------------------------------------------------------------- /src/interfaces/lido/ILido.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ILido is IERC20 { 7 | function getTotalShares() external view returns (uint256); 8 | 9 | function sharesOf(address _account) external view returns (uint256); 10 | 11 | function getSharesByPooledEth(uint256 _amount) external view returns (uint256); 12 | 13 | function getPooledEthByShares(uint256 _amount) external view returns (uint256); 14 | 15 | function submit(address _referral) external payable returns (uint256); 16 | } 17 | -------------------------------------------------------------------------------- /src/interfaces/lido/ILidoOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | pragma solidity >=0.8.4; 3 | 4 | interface ILidoOracle { 5 | function getLastCompletedReportDelta() 6 | external 7 | view 8 | returns (uint256 postTotalPooledEther, uint256 preTotalPooledEther, uint256 timeElapsed); 9 | } 10 | -------------------------------------------------------------------------------- /src/interfaces/lido/IWstETH.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPLv2 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface IWstETH is IERC20 { 7 | function wrap(uint256 _stETHAmount) external returns (uint256); 8 | 9 | function unwrap(uint256 _wstETHAmount) external returns (uint256); 10 | 11 | function getStETHByWstETH(uint256 _wstETHAmount) external view returns (uint256); 12 | 13 | function getWstETHByStETH(uint256 _stETHAmount) external view returns (uint256); 14 | } 15 | -------------------------------------------------------------------------------- /src/interfaces/liquity/IBorrowerOperations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface IBorrowerOperations { 5 | function openTrove(uint256 _maxFee, uint256 _LUSDAmount, address _upperHint, address _lowerHint) external payable; 6 | 7 | function closeTrove() external; 8 | 9 | function adjustTrove( 10 | uint256 _maxFee, 11 | uint256 _collWithdrawal, 12 | uint256 _debtChange, 13 | bool isDebtIncrease, 14 | address _upperHint, 15 | address _lowerHint 16 | ) external payable; 17 | 18 | function withdrawColl(uint256 _amount, address _upperHint, address _lowerHint) external; 19 | 20 | function claimCollateral() external; 21 | } 22 | -------------------------------------------------------------------------------- /src/interfaces/liquity/IHintHelpers.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface IHintHelpers { 5 | function getRedemptionHints(uint256 _LUSDamount, uint256 _price, uint256 _maxIterations) 6 | external 7 | view 8 | returns (address firstRedemptionHint, uint256 partialRedemptionHintNICR, uint256 truncatedLUSDamount); 9 | 10 | function getApproxHint(uint256 _CR, uint256 _numTrials, uint256 _inputRandomSeed) 11 | external 12 | view 13 | returns (address hintAddress, uint256 diff, uint256 latestRandomSeed); 14 | } 15 | -------------------------------------------------------------------------------- /src/interfaces/liquity/ILQTYStaking.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface ILQTYStaking { 5 | function stakes(address _user) external view returns (uint256); 6 | 7 | function stake(uint256 _LQTYamount) external; 8 | 9 | function unstake(uint256 _LQTYamount) external; 10 | } 11 | -------------------------------------------------------------------------------- /src/interfaces/liquity/ILiquityBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | import {IPriceFeed} from "./IPriceFeed.sol"; 5 | 6 | interface ILiquityBase { 7 | function priceFeed() external view returns (IPriceFeed); 8 | } 9 | -------------------------------------------------------------------------------- /src/interfaces/liquity/IPriceFeed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface IPriceFeed { 5 | function fetchPrice() external returns (uint256); 6 | } 7 | -------------------------------------------------------------------------------- /src/interfaces/liquity/ISortedTroves.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface ISortedTroves { 5 | function getLast() external view returns (address); 6 | 7 | function getNext(address _id) external view returns (address); 8 | 9 | function getPrev(address _id) external view returns (address); 10 | 11 | function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) 12 | external 13 | view 14 | returns (address, address); 15 | } 16 | -------------------------------------------------------------------------------- /src/interfaces/liquity/IStabilityPool.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface IStabilityPool { 5 | function provideToSP(uint256 _amount, address _frontEndTag) external; 6 | 7 | function withdrawFromSP(uint256 _amount) external; 8 | 9 | function getCompoundedLUSDDeposit(address _depositor) external view returns (uint256); 10 | } 11 | -------------------------------------------------------------------------------- /src/interfaces/liquity/ITroveManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | import {ILiquityBase} from "./ILiquityBase.sol"; 5 | 6 | // Common interface for the Trove Manager. 7 | interface ITroveManager is ILiquityBase { 8 | function getCurrentICR(address _borrower, uint256 _price) external view returns (uint256); 9 | 10 | function liquidate(address _borrower) external; 11 | 12 | function liquidateTroves(uint256 _n) external; 13 | 14 | function redeemCollateral( 15 | uint256 _LUSDAmount, 16 | address _firstRedemptionHint, 17 | address _upperPartialRedemptionHint, 18 | address _lowerPartialRedemptionHint, 19 | uint256 _partialRedemptionHintNICR, 20 | uint256 _maxIterations, 21 | uint256 _maxFee 22 | ) external; 23 | 24 | function getEntireDebtAndColl(address _borrower) 25 | external 26 | view 27 | returns (uint256 debt, uint256 coll, uint256 pendingLUSDDebtReward, uint256 pendingETHReward); 28 | 29 | function closeTrove(address _borrower) external; 30 | 31 | function getBorrowingRateWithDecay() external view returns (uint256); 32 | 33 | function getTroveStatus(address _borrower) external view returns (uint256); 34 | 35 | function getTCR(uint256 _price) external view returns (uint256); 36 | 37 | function checkRecoveryMode(uint256 _price) external view returns (bool); 38 | } 39 | -------------------------------------------------------------------------------- /src/interfaces/set/IController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | pragma solidity >=0.8.4; 3 | 4 | interface IController { 5 | function addSet(address _setToken) external; 6 | 7 | function feeRecipient() external view returns (address); 8 | 9 | function getModuleFee(address _module, uint256 _feeType) external view returns (uint256); 10 | 11 | function isModule(address _module) external view returns (bool); 12 | 13 | function isSet(address _setToken) external view returns (bool); 14 | 15 | function isSystemContract(address _contractAddress) external view returns (bool); 16 | 17 | function resourceId(uint256 _id) external view returns (address); 18 | } 19 | -------------------------------------------------------------------------------- /src/interfaces/set/IExchangeIssuance.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | import {ISetToken} from "./ISetToken.sol"; 6 | 7 | interface IExchangeIssuance { 8 | // Issues an exact amount of SetTokens using a given amount of ether. 9 | function issueExactSetFromETH(ISetToken _setToken, uint256 _amountSetToken) external payable returns (uint256); 10 | 11 | // Issues an exact amount of SetTokens for a given amount of input ERC-20 tokens. 12 | function issueExactSetFromToken( 13 | ISetToken _setToken, 14 | IERC20 _inputToken, 15 | uint256 _amountSetToken, 16 | uint256 _maxAmountInputToken 17 | ) external returns (uint256); 18 | 19 | // Issues SetTokens for an exact amount of input ERC-20 tokens. 20 | // The ERC-20 token must be approved by the sender to this contract. 21 | function issueSetForExactToken( 22 | ISetToken _setToken, 23 | IERC20 _inputToken, 24 | uint256 _amountInput, 25 | uint256 _minSetReceive 26 | ) external returns (uint256); 27 | 28 | // Issues SetTokens for an exact amount of input ether. 29 | function issueSetForExactETH(ISetToken _setToken, uint256 _minSetReceive) external payable returns (uint256); 30 | 31 | // Redeems an exact amount of SetTokens for an ERC-20 token. 32 | // The SetToken must be approved by the sender to this contract. 33 | function redeemExactSetForToken( 34 | ISetToken _setToken, 35 | IERC20 _outputToken, 36 | uint256 _amountSetToken, 37 | uint256 _minOutputReceive 38 | ) external returns (uint256); 39 | 40 | // Redeems an exact amount of SetTokens for ETH. 41 | // The SetToken must be approved by the sender to this contract. 42 | function redeemExactSetForETH(ISetToken _setToken, uint256 _amountSetToken, uint256 _minEthOut) 43 | external 44 | returns (uint256); 45 | } 46 | -------------------------------------------------------------------------------- /src/interfaces/set/ISetToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | pragma solidity >=0.8.4; 3 | 4 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 5 | 6 | interface ISetToken is IERC20 { 7 | /* ============ Enums ============ */ 8 | 9 | enum ModuleState { 10 | NONE, 11 | PENDING, 12 | INITIALIZED 13 | } 14 | 15 | /* ============ Structs ============ */ 16 | /** 17 | * The base definition of a SetToken Position 18 | * 19 | * @param component Address of token in the Position 20 | * @param module If not in default state, the address of associated module 21 | * @param unit Each unit is the # of components per 10^18 of a SetToken 22 | * @param positionState Position ENUM. Default is 0; External is 1 23 | * @param data Arbitrary data 24 | */ 25 | struct Position { 26 | address component; 27 | address module; 28 | int256 unit; 29 | uint8 positionState; 30 | bytes data; 31 | } 32 | 33 | /** 34 | * A struct that stores a component's cash position details and external positions 35 | * This data structure allows O(1) access to a component's cash position units and 36 | * virtual units. 37 | * 38 | * @param virtualUnit Virtual value of a component's DEFAULT position. Stored as virtual for efficiency 39 | * updating all units at once via the position multiplier. Virtual units are achieved 40 | * by dividing a "real" value by the "positionMultiplier" 41 | * @param componentIndex 42 | * @param externalPositionModules List of external modules attached to each external position. Each module 43 | * maps to an external position 44 | * @param externalPositions Mapping of module => ExternalPosition struct for a given component 45 | */ 46 | struct ComponentPosition { 47 | int256 virtualUnit; 48 | address[] externalPositionModules; 49 | mapping(address => ExternalPosition) externalPositions; 50 | } 51 | 52 | /** 53 | * A struct that stores a component's external position details including virtual unit and any 54 | * auxiliary data. 55 | * 56 | * @param virtualUnit Virtual value of a component's EXTERNAL position. 57 | * @param data Arbitrary data 58 | */ 59 | struct ExternalPosition { 60 | int256 virtualUnit; 61 | bytes data; 62 | } 63 | 64 | /* ============ Functions ============ */ 65 | 66 | function addComponent(address _component) external; 67 | 68 | function removeComponent(address _component) external; 69 | 70 | function editDefaultPositionUnit(address _component, int256 _realUnit) external; 71 | 72 | function addExternalPositionModule(address _component, address _positionModule) external; 73 | 74 | function removeExternalPositionModule(address _component, address _positionModule) external; 75 | 76 | function editExternalPositionUnit(address _component, address _positionModule, int256 _realUnit) external; 77 | 78 | function editExternalPositionData(address _component, address _positionModule, bytes calldata _data) external; 79 | 80 | function invoke(address _target, uint256 _value, bytes calldata _data) external returns (bytes memory); 81 | 82 | function editPositionMultiplier(int256 _newMultiplier) external; 83 | 84 | function mint(address _account, uint256 _quantity) external; 85 | 86 | function burn(address _account, uint256 _quantity) external; 87 | 88 | function lock() external; 89 | 90 | function unlock() external; 91 | 92 | function addModule(address _module) external; 93 | 94 | function removeModule(address _module) external; 95 | 96 | function initializeModule() external; 97 | 98 | function setManager(address _manager) external; 99 | 100 | function manager() external view returns (address); 101 | 102 | function moduleStates(address _module) external view returns (ModuleState); 103 | 104 | function getModules() external view returns (address[] memory); 105 | 106 | function getDefaultPositionRealUnit(address _component) external view returns (int256); 107 | 108 | function getExternalPositionRealUnit(address _component, address _positionModule) external view returns (int256); 109 | 110 | function getComponents() external view returns (address[] memory); 111 | 112 | function getExternalPositionModules(address _component) external view returns (address[] memory); 113 | 114 | function getExternalPositionData(address _component, address _positionModule) 115 | external 116 | view 117 | returns (bytes memory); 118 | 119 | function isExternalPositionModule(address _component, address _module) external view returns (bool); 120 | 121 | function isComponent(address _component) external view returns (bool); 122 | 123 | function positionMultiplier() external view returns (int256); 124 | 125 | function getPositions() external view returns (Position[] memory); 126 | 127 | function getTotalComponentRealUnits(address _component) external view returns (int256); 128 | 129 | function isInitializedModule(address _module) external view returns (bool); 130 | 131 | function isPendingModule(address _module) external view returns (bool); 132 | 133 | function isLocked() external view returns (bool); 134 | } 135 | -------------------------------------------------------------------------------- /src/interfaces/uniswapv3/IQuoter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.7.5; 3 | pragma abicoder v2; 4 | 5 | /// @title Quoter Interface 6 | /// @notice Supports quoting the calculated amounts from exact input or exact output swaps 7 | /// @dev These functions are not marked view because they rely on calling non-view functions and reverting 8 | /// to compute the result. They are also not gas efficient and should not be called on-chain. 9 | interface IQuoter { 10 | /// @notice Returns the amount out received for a given exact input swap without executing the swap 11 | /// @param path The path of the swap, i.e. each token pair and the pool fee 12 | /// @param amountIn The amount of the first token to swap 13 | /// @return amountOut The amount of the last token that would be received 14 | function quoteExactInput(bytes memory path, uint256 amountIn) external returns (uint256 amountOut); 15 | 16 | /// @notice Returns the amount out received for a given exact input but for a swap of a single pool 17 | /// @param tokenIn The token being swapped in 18 | /// @param tokenOut The token being swapped out 19 | /// @param fee The fee of the token pool to consider for the pair 20 | /// @param amountIn The desired input amount 21 | /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap 22 | /// @return amountOut The amount of `tokenOut` that would be received 23 | function quoteExactInputSingle( 24 | address tokenIn, 25 | address tokenOut, 26 | uint24 fee, 27 | uint256 amountIn, 28 | uint160 sqrtPriceLimitX96 29 | ) external returns (uint256 amountOut); 30 | 31 | /// @notice Returns the amount in required for a given exact output swap without executing the swap 32 | /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order 33 | /// @param amountOut The amount of the last token to receive 34 | /// @return amountIn The amount of first token required to be paid 35 | function quoteExactOutput(bytes memory path, uint256 amountOut) external returns (uint256 amountIn); 36 | 37 | /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool 38 | /// @param tokenIn The token being swapped in 39 | /// @param tokenOut The token being swapped out 40 | /// @param fee The fee of the token pool to consider for the pair 41 | /// @param amountOut The desired output amount 42 | /// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap 43 | /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` 44 | function quoteExactOutputSingle( 45 | address tokenIn, 46 | address tokenOut, 47 | uint24 fee, 48 | uint256 amountOut, 49 | uint160 sqrtPriceLimitX96 50 | ) external returns (uint256 amountIn); 51 | } 52 | -------------------------------------------------------------------------------- /src/interfaces/uniswapv3/ISwapRouter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.8.4; 3 | 4 | /// @title Router token swapping functionality 5 | /// @notice Functions for swapping tokens via Uniswap V3 6 | interface ISwapRouter { 7 | struct ExactInputSingleParams { 8 | address tokenIn; 9 | address tokenOut; 10 | uint24 fee; 11 | address recipient; 12 | uint256 deadline; 13 | uint256 amountIn; 14 | uint256 amountOutMinimum; 15 | uint160 sqrtPriceLimitX96; 16 | } 17 | 18 | /// @notice Swaps `amountIn` of one token for as much as possible of another token 19 | /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata 20 | /// @return amountOut The amount of the received token 21 | function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); 22 | 23 | struct ExactInputParams { 24 | bytes path; 25 | address recipient; 26 | uint256 deadline; 27 | uint256 amountIn; 28 | uint256 amountOutMinimum; 29 | } 30 | 31 | /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path 32 | /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata 33 | /// @return amountOut The amount of the received token 34 | function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); 35 | 36 | struct ExactOutputSingleParams { 37 | address tokenIn; 38 | address tokenOut; 39 | uint24 fee; 40 | address recipient; 41 | uint256 deadline; 42 | uint256 amountOut; 43 | uint256 amountInMaximum; 44 | uint160 sqrtPriceLimitX96; 45 | } 46 | 47 | /// @notice Swaps as little as possible of one token for `amountOut` of another token 48 | /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata 49 | /// @return amountIn The amount of the input token 50 | function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); 51 | 52 | struct ExactOutputParams { 53 | bytes path; 54 | address recipient; 55 | uint256 deadline; 56 | uint256 amountOut; 57 | uint256 amountInMaximum; 58 | } 59 | 60 | /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) 61 | /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata 62 | /// @return amountIn The amount of the input token 63 | function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); 64 | } 65 | -------------------------------------------------------------------------------- /src/interfaces/uniswapv3/callback/IUniswapV3SwapCallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.5.0; 3 | 4 | /// @title Callback for IUniswapV3PoolActions#swap 5 | /// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface 6 | interface IUniswapV3SwapCallback { 7 | /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. 8 | /// @dev In the implementation you must pay the pool tokens owed for the swap. 9 | /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. 10 | /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. 11 | /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by 12 | /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. 13 | /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by 14 | /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. 15 | /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call 16 | function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external; 17 | } 18 | -------------------------------------------------------------------------------- /src/interfaces/uniswapv3/pool/IUniswapV3PoolDerivedState.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.6.10; 3 | 4 | /// @title Pool state that is not stored 5 | /// @notice Contains view functions to provide information about the pool that is computed rather than stored on the 6 | /// blockchain. The functions here may have variable gas costs. 7 | interface IUniswapV3PoolDerivedState { 8 | /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp 9 | /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing 10 | /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, 11 | /// you must call it with secondsAgos = [3600, 0]. 12 | /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in 13 | /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. 14 | /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned 15 | /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp 16 | /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block 17 | /// timestamp 18 | function observe(uint32[] calldata secondsAgos) 19 | external 20 | view 21 | returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); 22 | 23 | /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range 24 | /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. 25 | /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first 26 | /// snapshot is taken and the second snapshot is taken. 27 | /// @param tickLower The lower tick of the range 28 | /// @param tickUpper The upper tick of the range 29 | /// @return tickCumulativeInside The snapshot of the tick accumulator for the range 30 | /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range 31 | /// @return secondsInside The snapshot of seconds per liquidity for the range 32 | function snapshotCumulativesInside(int24 tickLower, int24 tickUpper) 33 | external 34 | view 35 | returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside); 36 | } 37 | -------------------------------------------------------------------------------- /src/interfaces/uniswapv3/pool/IUniswapV3PoolImmutables.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | pragma solidity >=0.6.10; 3 | 4 | /// @title Pool state that never changes 5 | /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values 6 | interface IUniswapV3PoolImmutables { 7 | /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface 8 | /// @return The contract address 9 | function factory() external view returns (address); 10 | 11 | /// @notice The first of the two tokens of the pool, sorted by address 12 | /// @return The token contract address 13 | function token0() external view returns (address); 14 | 15 | /// @notice The second of the two tokens of the pool, sorted by address 16 | /// @return The token contract address 17 | function token1() external view returns (address); 18 | 19 | /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 20 | /// @return The fee 21 | function fee() external view returns (uint24); 22 | 23 | /// @notice The pool tick spacing 24 | /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive 25 | /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... 26 | /// This value is an int24 to avoid casting even though it is always positive. 27 | /// @return The tick spacing 28 | function tickSpacing() external view returns (int24); 29 | 30 | /// @notice The maximum amount of position liquidity that can use any tick in the range 31 | /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and 32 | /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool 33 | /// @return The max amount of liquidity per tick 34 | function maxLiquidityPerTick() external view returns (uint128); 35 | } 36 | -------------------------------------------------------------------------------- /src/interfaces/yearn/IYearnRegistry.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface IYearnRegistry { 5 | function latestVault(address token) external view returns (address); 6 | 7 | function tokens(uint256 index) external view returns (address); 8 | 9 | function vaults(address token, uint256 index) external view returns (address); 10 | 11 | function numTokens() external view returns (uint256); 12 | 13 | function numVaults(address token) external view returns (uint256); 14 | } 15 | -------------------------------------------------------------------------------- /src/interfaces/yearn/IYearnVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.8.4; 3 | 4 | interface IYearnVault { 5 | function deposit(uint256 amount) external returns (uint256); 6 | 7 | function withdraw(uint256 maxShares) external returns (uint256); 8 | 9 | function approve(address spender, uint256 amount) external returns (bool); 10 | 11 | function allowance(address owner, address spender) external view returns (uint256); 12 | 13 | function token() external view returns (address); 14 | 15 | function decimals() external view returns (uint256); 16 | 17 | function availableDepositLimit() external view returns (uint256); 18 | 19 | function pricePerShare() external view returns (uint256); 20 | 21 | function totalAssets() external view returns (uint256); 22 | } 23 | -------------------------------------------------------------------------------- /src/libraries/aave/DataTypes.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity >=0.8.4; 3 | 4 | library DataTypes { 5 | struct ReserveData { 6 | //stores the reserve configuration 7 | ReserveConfigurationMap configuration; 8 | //the liquidity index. Expressed in ray 9 | uint128 liquidityIndex; 10 | //variable borrow index. Expressed in ray 11 | uint128 variableBorrowIndex; 12 | //the current supply rate. Expressed in ray 13 | uint128 currentLiquidityRate; 14 | //the current variable borrow rate. Expressed in ray 15 | uint128 currentVariableBorrowRate; 16 | //the current stable borrow rate. Expressed in ray 17 | uint128 currentStableBorrowRate; 18 | uint40 lastUpdateTimestamp; 19 | //tokens addresses 20 | address aTokenAddress; 21 | address stableDebtTokenAddress; 22 | address variableDebtTokenAddress; 23 | //address of the interest rate strategy 24 | address interestRateStrategyAddress; 25 | //the id of the reserve. Represents the position in the list of the active reserves 26 | uint8 id; 27 | } 28 | 29 | struct ReserveDataV3 { 30 | //stores the reserve configuration 31 | ReserveConfigurationMap configuration; 32 | //the liquidity index. Expressed in ray 33 | uint128 liquidityIndex; 34 | //the current supply rate. Expressed in ray 35 | uint128 currentLiquidityRate; 36 | //variable borrow index. Expressed in ray 37 | uint128 variableBorrowIndex; 38 | //the current variable borrow rate. Expressed in ray 39 | uint128 currentVariableBorrowRate; 40 | //the current stable borrow rate. Expressed in ray 41 | uint128 currentStableBorrowRate; 42 | //timestamp of last update 43 | uint40 lastUpdateTimestamp; 44 | //the id of the reserve. Represents the position in the list of the active reserves 45 | uint16 id; 46 | //aToken address 47 | address aTokenAddress; 48 | //stableDebtToken address 49 | address stableDebtTokenAddress; 50 | //variableDebtToken address 51 | address variableDebtTokenAddress; 52 | //address of the interest rate strategy 53 | address interestRateStrategyAddress; 54 | //the current treasury balance, scaled 55 | uint128 accruedToTreasury; 56 | //the outstanding unbacked aTokens minted through the bridging feature 57 | uint128 unbacked; 58 | //the outstanding debt borrowed against this asset in isolation mode 59 | uint128 isolationModeTotalDebt; 60 | } 61 | 62 | struct ReserveConfigurationMap { 63 | //bit 0-15: LTV 64 | //bit 16-31: Liq. threshold 65 | //bit 32-47: Liq. bonus 66 | //bit 48-55: Decimals 67 | //bit 56: Reserve is active 68 | //bit 57: reserve is frozen 69 | //bit 58: borrowing is enabled 70 | //bit 59: stable rate borrowing enabled 71 | //bit 60-63: reserved 72 | //bit 64-79: reserve factor 73 | uint256 data; 74 | } 75 | 76 | struct UserConfigurationMap { 77 | uint256 data; 78 | } 79 | 80 | enum InterestRateMode { 81 | NONE, 82 | STABLE, 83 | VARIABLE 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/libraries/aave/WadRayMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: agpl-3.0 2 | pragma solidity >=0.6.10; 3 | 4 | /** 5 | * @title WadRayMath library 6 | * @author Aave 7 | * @notice Provides functions to perform calculations with Wad and Ray units 8 | * @dev Provides mul and div function for wads (decimal numbers with 18 digits of precision) and rays (decimal numbers 9 | * with 27 digits of precision) 10 | * @dev Operations are rounded. If a value is >=.5, will be rounded up, otherwise rounded down. 11 | * 12 | */ 13 | library WadRayMath { 14 | // HALF_WAD and HALF_RAY expressed with extended notation as constant with operations are not supported in Yul assembly 15 | uint256 internal constant WAD = 1e18; 16 | uint256 internal constant HALF_WAD = 0.5e18; 17 | 18 | uint256 internal constant RAY = 1e27; 19 | uint256 internal constant HALF_RAY = 0.5e27; 20 | 21 | uint256 internal constant WAD_RAY_RATIO = 1e9; 22 | 23 | /** 24 | * @dev Multiplies two wad, rounding half up to the nearest wad 25 | * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328 26 | * @param a Wad 27 | * @param b Wad 28 | * @return c = a*b, in wad 29 | * 30 | */ 31 | function wadMul(uint256 a, uint256 b) internal pure returns (uint256 c) { 32 | // to avoid overflow, a <= (type(uint256).max - HALF_WAD) / b 33 | assembly { 34 | if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_WAD), b))))) { revert(0, 0) } 35 | 36 | c := div(add(mul(a, b), HALF_WAD), WAD) 37 | } 38 | } 39 | 40 | /** 41 | * @dev Divides two wad, rounding half up to the nearest wad 42 | * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328 43 | * @param a Wad 44 | * @param b Wad 45 | * @return c = a/b, in wad 46 | * 47 | */ 48 | function wadDiv(uint256 a, uint256 b) internal pure returns (uint256 c) { 49 | // to avoid overflow, a <= (type(uint256).max - halfB) / WAD 50 | assembly { 51 | if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), WAD))))) { revert(0, 0) } 52 | 53 | c := div(add(mul(a, WAD), div(b, 2)), b) 54 | } 55 | } 56 | 57 | /** 58 | * @notice Multiplies two ray, rounding half up to the nearest ray 59 | * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328 60 | * @param a Ray 61 | * @param b Ray 62 | * @return c = a raymul b 63 | * 64 | */ 65 | function rayMul(uint256 a, uint256 b) internal pure returns (uint256 c) { 66 | // to avoid overflow, a <= (type(uint256).max - HALF_RAY) / b 67 | assembly { 68 | if iszero(or(iszero(b), iszero(gt(a, div(sub(not(0), HALF_RAY), b))))) { revert(0, 0) } 69 | 70 | c := div(add(mul(a, b), HALF_RAY), RAY) 71 | } 72 | } 73 | 74 | /** 75 | * @notice Divides two ray, rounding half up to the nearest ray 76 | * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328 77 | * @param a Ray 78 | * @param b Ray 79 | * @return c = a raydiv b 80 | * 81 | */ 82 | function rayDiv(uint256 a, uint256 b) internal pure returns (uint256 c) { 83 | // to avoid overflow, a <= (type(uint256).max - halfB) / RAY 84 | assembly { 85 | if or(iszero(b), iszero(iszero(gt(a, div(sub(not(0), div(b, 2)), RAY))))) { revert(0, 0) } 86 | 87 | c := div(add(mul(a, RAY), div(b, 2)), b) 88 | } 89 | } 90 | 91 | /** 92 | * @dev Casts ray down to wad 93 | * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328 94 | * @param a Ray 95 | * @return b = a converted to wad, rounded half up to the nearest wad 96 | * 97 | */ 98 | function rayToWad(uint256 a) internal pure returns (uint256 b) { 99 | assembly { 100 | b := div(a, WAD_RAY_RATIO) 101 | let remainder := mod(a, WAD_RAY_RATIO) 102 | if iszero(lt(remainder, div(WAD_RAY_RATIO, 2))) { b := add(b, 1) } 103 | } 104 | } 105 | 106 | /** 107 | * @dev Converts wad up to ray 108 | * @dev assembly optimized for improved gas savings, see https://twitter.com/transmissions11/status/1451131036377571328 109 | * @param a Wad 110 | * @return b = a converted in ray 111 | * 112 | */ 113 | function wadToRay(uint256 a) internal pure returns (uint256 b) { 114 | // to avoid overflow, b/WAD_RAY_RATIO == a 115 | assembly { 116 | b := mul(a, WAD_RAY_RATIO) 117 | 118 | if iszero(eq(div(b, WAD_RAY_RATIO), a)) { revert(0, 0) } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/scripts/FinalisationScript.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {Test} from "forge-std/Test.sol"; 6 | 7 | interface IMulticall { 8 | struct Call { 9 | address target; 10 | bytes callData; 11 | } 12 | 13 | function aggregate(Call[] memory _calls) external returns (uint256 blockNumber, bytes[] memory returnData); 14 | } 15 | 16 | contract FinalisationScript is Test { 17 | IMulticall private constant MULTI_CALL = IMulticall(0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441); 18 | address private constant ROLLUP_PROCESSOR = 0xFF1F2B4ADb9dF6FC8eAFecDcbF96A2B351680455; 19 | 20 | // TODO: update the array with actual nonces 21 | uint256[] private interactionNonces = [100, 101, 102]; 22 | 23 | function finaliseAll() public { 24 | IMulticall.Call[] memory calls = new IMulticall.Call[](interactionNonces.length); 25 | for (uint256 i = 0; i < interactionNonces.length; i++) { 26 | bytes memory callData = 27 | abi.encodeWithSignature("processAsyncDefiInteraction(uint256)", interactionNonces[i]); 28 | calls[i] = IMulticall.Call(ROLLUP_PROCESSOR, callData); 29 | } 30 | vm.broadcast(); 31 | MULTI_CALL.aggregate(calls); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/aztec/base/BridgeTestBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {Test, Vm} from "forge-std/Test.sol"; 6 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 7 | import {IRollupProcessorV2} from "rollup-encoder/interfaces/IRollupProcessorV2.sol"; 8 | import {ISubsidy} from "../../../aztec/interfaces/ISubsidy.sol"; 9 | import {RollupEncoder} from "rollup-encoder/RollupEncoder.sol"; 10 | 11 | /** 12 | * @notice Helper contract that allow us to test bridges against the live rollup by sending mock rollups with defi interactions 13 | * The helper will setup the state and impersonate parties to allow easy interaction with the rollup 14 | * @author Lasse Herskind 15 | */ 16 | abstract contract BridgeTestBase is Test { 17 | IRollupProcessorV2 internal constant ROLLUP_PROCESSOR = 18 | IRollupProcessorV2(0xFF1F2B4ADb9dF6FC8eAFecDcbF96A2B351680455); 19 | ISubsidy internal constant SUBSIDY = ISubsidy(0xABc30E831B5Cc173A9Ed5941714A7845c909e7fA); 20 | address internal constant MULTI_SIG = 0xE298a76986336686CC3566469e3520d23D1a8aaD; 21 | bytes32 private constant LISTER_ROLE = 0xf94103142c1baabe9ac2b5d1487bf783de9e69cfeea9a72f5c9c94afd7877b8c; 22 | 23 | RollupEncoder internal immutable ROLLUP_ENCODER; 24 | 25 | AztecTypes.AztecAsset internal emptyAsset; 26 | 27 | constructor() { 28 | ROLLUP_ENCODER = new RollupEncoder(address(ROLLUP_PROCESSOR)); 29 | 30 | // Granting multi-sig admin role rather than switching to the lister to not break fixed block tests. 31 | vm.prank(0xE298a76986336686CC3566469e3520d23D1a8aaD); 32 | (bool success,) = address(ROLLUP_PROCESSOR).call( 33 | abi.encodeWithSignature("grantRole(bytes32,address)", LISTER_ROLE, MULTI_SIG) 34 | ); 35 | if (!success) { 36 | revert("Failed to give multisig lister role"); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/bridges/element/HeapTestContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {MinHeap} from "../../../bridges/element/MinHeap.sol"; 6 | 7 | contract HeapTestContract { 8 | using MinHeap for MinHeap.MinHeapData; 9 | 10 | MinHeap.MinHeapData private heap; 11 | 12 | constructor(uint32 _initialSize) { 13 | heap.initialise(_initialSize); 14 | } 15 | 16 | function add(uint64 _value) public { 17 | heap.add(_value); 18 | } 19 | 20 | function remove(uint64 _value) public { 21 | heap.remove(_value); 22 | } 23 | 24 | function pop() public { 25 | heap.pop(); 26 | } 27 | 28 | function min() public view returns (uint64) { 29 | return heap.min(); 30 | } 31 | 32 | function size() public view returns (uint256) { 33 | return heap.size(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/bridges/element/MockDeploymentValidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | import "../../../interfaces/element/IDeploymentValidator.sol"; 5 | 6 | // taken from the real Element deployment validator contract 7 | contract MockDeploymentValidator is IDeploymentValidator { 8 | // a mapping of wrapped position contracts deployed by Element 9 | mapping(address => bool) public wrappedPositions; 10 | // a mapping of pool contracts deployed by Element 11 | mapping(address => bool) public pools; 12 | // a mapping of wrapped position + pool pairs that are deployed by Element 13 | // we keccak256 hash these tuples together to serve as the mapping keys 14 | mapping(bytes32 => bool) public pairs; 15 | 16 | /// @notice Constructs this contract and stores needed data 17 | constructor() {} 18 | 19 | /// @notice adds a wrapped position address to the mapping 20 | /// @param wrappedPosition The wrapped position contract address 21 | function validateWPAddress(address wrappedPosition) external override { 22 | // add address to mapping to indicating it was deployed by Element 23 | wrappedPositions[wrappedPosition] = true; 24 | } 25 | 26 | /// @notice adds a wrapped position address to the mapping 27 | /// @param pool the pool contract address 28 | function validatePoolAddress(address pool) external override { 29 | // add address to mapping to indicating it was deployed by Element 30 | pools[pool] = true; 31 | } 32 | 33 | /// @notice adds a wrapped position + pool pair of addresses to mapping 34 | /// @param wrappedPosition the wrapped position contract address 35 | /// @param pool the pool contract address 36 | function validateAddresses(address wrappedPosition, address pool) external override { 37 | // has together the contract addresses 38 | bytes32 data = keccak256(abi.encodePacked(wrappedPosition, pool)); 39 | // add the hashed pair into the mapping 40 | pairs[data] = true; 41 | } 42 | 43 | /// @notice checks to see if the address has been validated 44 | /// @param wrappedPosition the address to check 45 | /// @return true if validated, false if not 46 | function checkWPValidation(address wrappedPosition) external view override returns (bool) { 47 | return wrappedPositions[wrappedPosition]; 48 | } 49 | 50 | /// @notice checks to see if the address has been validated 51 | /// @param pool the address to check 52 | /// @return true if validated, false if not 53 | function checkPoolValidation(address pool) external view override returns (bool) { 54 | return pools[pool]; 55 | } 56 | 57 | /// @notice checks to see if the pair of addresses have been validated 58 | /// @param wrappedPosition the wrapped position address to check 59 | /// @param pool the pool address to check 60 | /// @return true if validated, false if not 61 | function checkPairValidation(address wrappedPosition, address pool) external view override returns (bool) { 62 | bytes32 data = keccak256(abi.encodePacked(wrappedPosition, pool)); 63 | return pairs[data]; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/test/bridges/erc4626/mocks/WETHVault.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; 7 | import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; 8 | 9 | contract WETHVault is 10 | ERC20("WETH vault", "vWETH"), 11 | ERC4626(IERC20Metadata(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2)) 12 | { 13 | function decimals() public pure override(ERC20, ERC4626) returns (uint8) { 14 | return 18; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/bridges/example/ExampleE2E.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BridgeTestBase} from "./../../aztec/base/BridgeTestBase.sol"; 6 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 7 | 8 | // Example-specific imports 9 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 10 | import {ExampleBridge} from "../../../bridges/example/ExampleBridge.sol"; 11 | import {ErrorLib} from "../../../bridges/base/ErrorLib.sol"; 12 | 13 | /** 14 | * @notice The purpose of this test is to test the bridge in an environment that is as close to the final deployment 15 | * as possible without spinning up all the rollup infrastructure (sequencer, proof generator etc.). 16 | */ 17 | contract ExampleE2ETest is BridgeTestBase { 18 | address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; 19 | address private constant BENEFICIARY = address(11); 20 | 21 | // The reference to the example bridge 22 | ExampleBridge internal bridge; 23 | // To store the id of the example bridge after being added 24 | uint256 private id; 25 | 26 | function setUp() public { 27 | // Deploy a new example bridge 28 | bridge = new ExampleBridge(address(ROLLUP_PROCESSOR)); 29 | 30 | // Use the label cheatcode to mark the address with "Example Bridge" in the traces 31 | vm.label(address(bridge), "Example Bridge"); 32 | 33 | // Impersonate the multi-sig to add a new bridge 34 | vm.startPrank(MULTI_SIG); 35 | 36 | // List the example-bridge with a gasLimit of 120k 37 | // WARNING: If you set this value too low the interaction will fail for seemingly no reason! 38 | // OTOH if you se it too high bridge users will pay too much 39 | ROLLUP_PROCESSOR.setSupportedBridge(address(bridge), 120000); 40 | 41 | // List USDC with a gasLimit of 100k 42 | // Note: necessary for assets which are not already registered on RollupProcessor 43 | // Call https://etherscan.io/address/0xFF1F2B4ADb9dF6FC8eAFecDcbF96A2B351680455#readProxyContract#F25 to get 44 | // addresses of all the listed ERC20 tokens 45 | ROLLUP_PROCESSOR.setSupportedAsset(USDC, 100000); 46 | 47 | vm.stopPrank(); 48 | 49 | // Fetch the id of the example bridge 50 | id = ROLLUP_PROCESSOR.getSupportedBridgesLength(); 51 | 52 | // Subsidize the bridge when used with USDC and register a beneficiary 53 | AztecTypes.AztecAsset memory usdcAsset = ROLLUP_ENCODER.getRealAztecAsset(USDC); 54 | uint256 criteria = bridge.computeCriteria(usdcAsset, emptyAsset, usdcAsset, emptyAsset, 0); 55 | uint32 gasPerMinute = 200; 56 | SUBSIDY.subsidize{value: 1 ether}(address(bridge), criteria, gasPerMinute); 57 | 58 | SUBSIDY.registerBeneficiary(BENEFICIARY); 59 | 60 | // Set the rollupBeneficiary on BridgeTestBase so that it gets included in the proofData 61 | ROLLUP_ENCODER.setRollupBeneficiary(BENEFICIARY); 62 | } 63 | 64 | // @dev In order to avoid overflows we set _depositAmount to be uint96 instead of uint256. 65 | function testExampleBridgeE2ETest(uint96 _depositAmount) public { 66 | vm.assume(_depositAmount > 1); 67 | vm.warp(block.timestamp + 1 days); 68 | 69 | // Use the helper function to fetch the support AztecAsset for DAI 70 | AztecTypes.AztecAsset memory usdcAsset = ROLLUP_ENCODER.getRealAztecAsset(address(USDC)); 71 | 72 | // Mint the depositAmount of Dai to rollupProcessor 73 | deal(USDC, address(ROLLUP_PROCESSOR), _depositAmount); 74 | 75 | // Computes the encoded data for the specific bridge interaction 76 | ROLLUP_ENCODER.defiInteractionL2(id, usdcAsset, emptyAsset, usdcAsset, emptyAsset, 0, _depositAmount); 77 | 78 | // Execute the rollup with the bridge interaction. Ensure that event as seen above is emitted. 79 | (uint256 outputValueA, uint256 outputValueB, bool isAsync) = ROLLUP_ENCODER.processRollupAndGetBridgeResult(); 80 | 81 | // Note: Unlike in unit tests there is no need to manually transfer the tokens - RollupProcessor does this 82 | 83 | // Check the output values are as expected 84 | assertEq(outputValueA, _depositAmount, "outputValueA doesn't equal deposit"); 85 | assertEq(outputValueB, 0, "Non-zero outputValueB"); 86 | assertFalse(isAsync, "Bridge is not synchronous"); 87 | 88 | // Check that the balance of the rollup is same as before interaction (bridge just sends funds back) 89 | assertEq(_depositAmount, IERC20(USDC).balanceOf(address(ROLLUP_PROCESSOR)), "Balances must match"); 90 | 91 | // Perform a second rollup with half the deposit, perform similar checks. 92 | uint256 secondDeposit = _depositAmount / 2; 93 | 94 | ROLLUP_ENCODER.defiInteractionL2(id, usdcAsset, emptyAsset, usdcAsset, emptyAsset, 0, secondDeposit); 95 | 96 | // Execute the rollup with the bridge interaction. Ensure that event as seen above is emitted. 97 | (outputValueA, outputValueB, isAsync) = ROLLUP_ENCODER.processRollupAndGetBridgeResult(); 98 | 99 | // Check the output values are as expected 100 | assertEq(outputValueA, secondDeposit, "outputValueA doesn't equal second deposit"); 101 | assertEq(outputValueB, 0, "Non-zero outputValueB"); 102 | assertFalse(isAsync, "Bridge is not synchronous"); 103 | 104 | // Check that the balance of the rollup is same as before interaction (bridge just sends funds back) 105 | assertEq(_depositAmount, IERC20(USDC).balanceOf(address(ROLLUP_PROCESSOR)), "Balances must match"); 106 | 107 | assertGt(SUBSIDY.claimableAmount(BENEFICIARY), 0, "Claimable was not updated"); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/bridges/liquity/StabilityPoolBridgeE2E.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {BridgeTestBase} from "./../../aztec/base/BridgeTestBase.sol"; 9 | import {ErrorLib} from "../../../bridges/base/ErrorLib.sol"; 10 | 11 | import {StabilityPoolBridge} from "../../../bridges/liquity/StabilityPoolBridge.sol"; 12 | 13 | contract StabilityPoolBridgeE2ETest is BridgeTestBase { 14 | IERC20 public constant LUSD = IERC20(0x5f98805A4E8be255a32880FDeC7F6728C6568bA0); 15 | 16 | // The reference to the stability pool bridge 17 | StabilityPoolBridge private bridge; 18 | address private stabilityPool; 19 | 20 | // To store the id of the stability pool bridge after being added 21 | uint256 private id; 22 | 23 | function setUp() public { 24 | // Deploy a new stability pool bridge and set approvals 25 | bridge = new StabilityPoolBridge(address(ROLLUP_PROCESSOR), address(0)); 26 | bridge.setApprovals(); 27 | 28 | stabilityPool = address(bridge.STABILITY_POOL()); 29 | 30 | // Use the label cheat-code to mark the address with stability pool bridge in the traces 31 | vm.label(address(bridge), "StabilityPoolBridge"); 32 | vm.label(stabilityPool, "StabilityPool"); 33 | 34 | // Impersonate the multi-sig to add a new bridge 35 | vm.startPrank(MULTI_SIG); 36 | 37 | // List the staking-bridge with a gasLimit of 350k 38 | ROLLUP_PROCESSOR.setSupportedBridge(address(bridge), 1000000); 39 | 40 | // List the assets with a gasLimit of 100k 41 | ROLLUP_PROCESSOR.setSupportedAsset(address(LUSD), 100000); 42 | ROLLUP_PROCESSOR.setSupportedAsset(address(bridge), 100000); 43 | 44 | vm.stopPrank(); 45 | 46 | // Fetch the id of the stability pool bridge 47 | id = ROLLUP_PROCESSOR.getSupportedBridgesLength(); 48 | 49 | // Reset ETH balance to 0 to make accounting easier 50 | deal(address(bridge), 0); 51 | } 52 | 53 | // @dev In order to avoid overflows we set _depositAmount to be uint96 instead of uint256. 54 | function testFullDepositWithdrawalE2E(uint96 _depositAmount) public { 55 | vm.assume(_depositAmount > 1); 56 | 57 | // Use the helper function to fetch Aztec assets 58 | AztecTypes.AztecAsset memory lusdAsset = ROLLUP_ENCODER.getRealAztecAsset(address(LUSD)); 59 | AztecTypes.AztecAsset memory spbAsset = ROLLUP_ENCODER.getRealAztecAsset(address(bridge)); 60 | 61 | // DEPOSIT 62 | // Mint the depositAmount of LUSD to rollupProcessor 63 | deal(address(LUSD), address(ROLLUP_PROCESSOR), _depositAmount); 64 | 65 | // Compute deposit calldata 66 | uint256 bridgeCallData = 67 | ROLLUP_ENCODER.defiInteractionL2(id, lusdAsset, emptyAsset, spbAsset, emptyAsset, 0, _depositAmount); 68 | 69 | uint256 stabilityPoolBalanceBefore = LUSD.balanceOf(stabilityPool); 70 | 71 | ROLLUP_ENCODER.registerEventToBeChecked( 72 | bridgeCallData, ROLLUP_ENCODER.getNextNonce(), _depositAmount, _depositAmount, 0, true, "" 73 | ); 74 | ROLLUP_ENCODER.processRollup(); 75 | 76 | assertGe( 77 | LUSD.balanceOf(stabilityPool) - stabilityPoolBalanceBefore, 78 | _depositAmount, 79 | "Stability pool balance didn't rise enough" 80 | ); 81 | assertEq( 82 | bridge.balanceOf(address(ROLLUP_PROCESSOR)), _depositAmount, "Incorrect SPB balance of rollup processor" 83 | ); 84 | 85 | // WITHDRAWAL 86 | // Compute withdrawal calldata 87 | ROLLUP_ENCODER.defiInteractionL2(id, spbAsset, emptyAsset, lusdAsset, emptyAsset, 0, _depositAmount); 88 | 89 | uint256 processorBalanceBefore = LUSD.balanceOf(address(ROLLUP_PROCESSOR)); 90 | 91 | (uint256 outputValueA, uint256 outputValueB,) = ROLLUP_ENCODER.processRollupAndGetBridgeResult(); 92 | 93 | assertGe(outputValueA, _depositAmount, "Output value not bigger than deposit"); 94 | assertEq(outputValueB, 0, "Output value B is not 0"); 95 | 96 | assertGe( 97 | LUSD.balanceOf(address(ROLLUP_PROCESSOR)) - processorBalanceBefore, 98 | _depositAmount, 99 | "Rollup processor balance didn't rise enough" 100 | ); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/test/bridges/liquity/StabilityPoolBridgeInternal.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import {TestUtil} from "./utils/TestUtil.sol"; 8 | import {StabilityPoolBridge} from "../../../bridges/liquity/StabilityPoolBridge.sol"; 9 | 10 | contract StabilityPoolBridgeTestInternal is TestUtil, StabilityPoolBridge(address(0), address(0)) { 11 | function setUp() public { 12 | _setUpTokensAndLabels(); 13 | rollupProcessor = address(this); 14 | 15 | // solhint-disable-next-line 16 | require(IERC20(WETH).approve(address(UNI_ROUTER), type(uint256).max), "WETH_APPROVE_FAILED"); 17 | // solhint-disable-next-line 18 | require(IERC20(LQTY).approve(address(UNI_ROUTER), type(uint256).max), "LQTY_APPROVE_FAILED"); 19 | // solhint-disable-next-line 20 | require(IERC20(USDC).approve(address(UNI_ROUTER), type(uint256).max), "USDC_APPROVE_FAILED"); 21 | 22 | // EIP-1087 optimization related mints 23 | deal(tokens["LQTY"].addr, address(this), 1); 24 | deal(tokens["LUSD"].addr, address(this), 1); 25 | deal(tokens["WETH"].addr, address(this), 1); 26 | } 27 | 28 | function testSwapRewardsOnUni() public { 29 | deal(tokens["LQTY"].addr, address(this), 1e21); 30 | 31 | // Note: to make the tests faster I will burn most of the ETH. This contract gets 79 million ETH by default. 32 | // This makes swapping through Uni v3 slow as it has to loop through the ticks for many seconds 33 | payable(address(0)).transfer(address(this).balance - 1 ether); 34 | 35 | uint256 depositedLUSDBeforeSwap = STABILITY_POOL.getCompoundedLUSDDeposit(address(this)); 36 | _swapRewardsToLUSDAndDeposit(false); 37 | uint256 depositedLUSDAfterSwap = STABILITY_POOL.getCompoundedLUSDDeposit(address(this)); 38 | 39 | // Verify that rewards were swapped for non-zero amount and correctly staked 40 | assertGt(depositedLUSDAfterSwap, depositedLUSDBeforeSwap); 41 | 42 | // Verify that all the rewards were swapped to LUSD 43 | assertEq(tokens["WETH"].erc.balanceOf(address(this)), DUST); 44 | assertEq(tokens["LQTY"].erc.balanceOf(address(this)), DUST); 45 | assertEq(tokens["LUSD"].erc.balanceOf(address(this)), DUST); 46 | assertEq(address(this).balance, 0); 47 | } 48 | 49 | function testUrgentModeOnSwap1() public { 50 | // Destroy the pools reserves in order for the swap to fail 51 | deal(WETH, LQTY_ETH_POOL, 0); 52 | deal(LQTY, address(this), 1e21); 53 | 54 | // Call shouldn't revert even though swap 1 fails 55 | _swapRewardsToLUSDAndDeposit(true); 56 | } 57 | 58 | function testUrgentModeOnSwap2() public { 59 | // Destroy the pools reserves in order for the swap to fail 60 | deal(USDC, USDC_ETH_POOL, 0); 61 | deal(LQTY, address(this), 1e21); 62 | 63 | // Call shouldn't revert even though swap 1 fails 64 | _swapRewardsToLUSDAndDeposit(true); 65 | } 66 | 67 | function testUrgentModeOnSwap3() public { 68 | // Destroy the pools reserves in order for the swap to fail 69 | deal(LUSD, LUSD_USDC_POOL, 0); 70 | deal(LQTY, address(this), 1e21); 71 | 72 | // Call shouldn't revert even though swap 1 fails 73 | _swapRewardsToLUSDAndDeposit(true); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/bridges/liquity/StakingBridgeE2E.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | 7 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 8 | import {BridgeTestBase} from "./../../aztec/base/BridgeTestBase.sol"; 9 | import {ErrorLib} from "../../../bridges/base/ErrorLib.sol"; 10 | 11 | import {StakingBridge} from "../../../bridges/liquity/StakingBridge.sol"; 12 | 13 | contract StakingBridgeE2ETest is BridgeTestBase { 14 | IERC20 public constant LQTY = IERC20(0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D); 15 | 16 | // The reference to the staking bridge 17 | StakingBridge private bridge; 18 | address private stakingContract; 19 | 20 | // To store the id of the staking bridge after being added 21 | uint256 private id; 22 | 23 | function setUp() public { 24 | // Deploy a new staking bridge and set approvals 25 | bridge = new StakingBridge(address(ROLLUP_PROCESSOR)); 26 | bridge.setApprovals(); 27 | 28 | stakingContract = address(bridge.STAKING_CONTRACT()); 29 | 30 | // Use the label cheatcode to mark the address with "Staking Bridge" in the traces 31 | vm.label(address(bridge), "StakingBridge"); 32 | vm.label(stakingContract, "LQTYStakingContract"); 33 | 34 | // Impersonate the multi-sig to add a new bridge 35 | vm.startPrank(MULTI_SIG); 36 | 37 | // List the staking-bridge with a gasLimit of 500k 38 | ROLLUP_PROCESSOR.setSupportedBridge(address(bridge), 500000); 39 | 40 | // List the assets with a gasLimit of 100k 41 | ROLLUP_PROCESSOR.setSupportedAsset(address(LQTY), 100000); 42 | ROLLUP_PROCESSOR.setSupportedAsset(address(bridge), 100000); 43 | 44 | vm.stopPrank(); 45 | 46 | // Fetch the id of the staking bridge 47 | id = ROLLUP_PROCESSOR.getSupportedBridgesLength(); 48 | } 49 | 50 | // @dev In order to avoid overflows we set _depositAmount to be uint96 instead of uint256. 51 | function testFullDepositWithdrawalE2E(uint96 _depositAmount) public { 52 | vm.assume(_depositAmount > 1); 53 | 54 | // Use the helper function to fetch Aztec assets 55 | AztecTypes.AztecAsset memory lqtyAsset = ROLLUP_ENCODER.getRealAztecAsset(address(LQTY)); 56 | AztecTypes.AztecAsset memory sbAsset = ROLLUP_ENCODER.getRealAztecAsset(address(bridge)); 57 | 58 | // DEPOSIT 59 | // Mint the depositAmount of LQTY to rollupProcessor 60 | deal(address(LQTY), address(ROLLUP_PROCESSOR), _depositAmount); 61 | 62 | // Compute deposit calldata 63 | uint256 bridgeCallData = 64 | ROLLUP_ENCODER.defiInteractionL2(id, lqtyAsset, emptyAsset, sbAsset, emptyAsset, 0, _depositAmount); 65 | 66 | uint256 stakingBalanceBefore = LQTY.balanceOf(stakingContract); 67 | 68 | ROLLUP_ENCODER.registerEventToBeChecked( 69 | bridgeCallData, ROLLUP_ENCODER.getNextNonce(), _depositAmount, _depositAmount, 0, true, "" 70 | ); 71 | ROLLUP_ENCODER.processRollup(); 72 | 73 | assertGe( 74 | LQTY.balanceOf(stakingContract) - stakingBalanceBefore, 75 | _depositAmount, 76 | "Staking contract balance didn't rise enough" 77 | ); 78 | assertEq( 79 | bridge.balanceOf(address(ROLLUP_PROCESSOR)), _depositAmount, "Incorrect SB balance of rollup processor" 80 | ); 81 | 82 | // WITHDRAWAL 83 | // Compute withdrawal calldata 84 | ROLLUP_ENCODER.defiInteractionL2(id, sbAsset, emptyAsset, lqtyAsset, emptyAsset, 0, _depositAmount); 85 | 86 | uint256 processorBalanceBefore = LQTY.balanceOf(address(ROLLUP_PROCESSOR)); 87 | 88 | (uint256 outputValueA, uint256 outputValueB,) = ROLLUP_ENCODER.processRollupAndGetBridgeResult(); 89 | 90 | assertGe(outputValueA, _depositAmount, "Output value not bigger than deposit"); 91 | assertEq(outputValueB, 0, "Output value B is not 0"); 92 | 93 | assertGe( 94 | LQTY.balanceOf(address(ROLLUP_PROCESSOR)) - processorBalanceBefore, 95 | _depositAmount, 96 | "Rollup processor balance didn't rise enough" 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/test/bridges/liquity/StakingBridgeInternal.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {ErrorLib} from "../../../bridges/base/ErrorLib.sol"; 7 | import {StakingBridge} from "../../../bridges/liquity/StakingBridge.sol"; 8 | import {TestUtil} from "./utils/TestUtil.sol"; 9 | 10 | contract StakingBridgeTestInternal is TestUtil, StakingBridge(address(0)) { 11 | function setUp() public { 12 | _setUpTokensAndLabels(); 13 | rollupProcessor = address(this); 14 | 15 | // solhint-disable-next-line 16 | require(IERC20(WETH).approve(address(UNI_ROUTER), type(uint256).max), "WETH_APPROVE_FAILED"); 17 | // solhint-disable-next-line 18 | require(IERC20(LUSD).approve(address(UNI_ROUTER), type(uint256).max), "LUSD_APPROVE_FAILED"); 19 | // solhint-disable-next-line 20 | require(IERC20(USDC).approve(address(UNI_ROUTER), type(uint256).max), "USDC_APPROVE_FAILED"); 21 | 22 | // EIP-1087 optimization related mints 23 | deal(tokens["LUSD"].addr, address(this), 1); 24 | deal(tokens["LQTY"].addr, address(this), 1); 25 | deal(tokens["WETH"].addr, address(this), 1); 26 | } 27 | 28 | function testSwapRewardsToLQTY() public { 29 | deal(tokens["LUSD"].addr, address(this), 1e21); 30 | 31 | // Note: to make the tests faster I will burn most of the ETH. This contract gets 79 million ETH by default. 32 | // This makes swapping through Uni v3 slow as it has to loop through the ticks for many seconds 33 | payable(address(0)).transfer(address(this).balance - 1 ether); 34 | 35 | uint256 stakedLQTYBeforeSwap = STAKING_CONTRACT.stakes(address(this)); 36 | _swapRewardsToLQTYAndStake(false); 37 | uint256 stakedLQTYAfterSwap = STAKING_CONTRACT.stakes(address(this)); 38 | 39 | // Verify that rewards were swapped for non-zero amount and correctly staked 40 | assertGt(stakedLQTYAfterSwap, stakedLQTYBeforeSwap); 41 | 42 | // Verify that all the rewards were swapped and staked 43 | assertEq(tokens["WETH"].erc.balanceOf(address(this)), DUST); 44 | assertEq(tokens["LUSD"].erc.balanceOf(address(this)), DUST); 45 | assertEq(tokens["LQTY"].erc.balanceOf(address(this)), DUST); 46 | assertEq(address(this).balance, 0); 47 | } 48 | 49 | function testUrgentModeOnSwap1() public { 50 | // Destroy the pools reserves in order for the swap to fail 51 | deal(USDC, LUSD_USDC_POOL, 0); 52 | deal(LUSD, address(this), 1e21); 53 | 54 | // Call shouldn't revert even though the swap fails 55 | _swapRewardsToLQTYAndStake(true); 56 | } 57 | 58 | function testUrgentModeOnSwap2() public { 59 | // Destroy the pools reserves in order for the swap to fail 60 | deal(WETH, USDC_ETH_POOL, 0); 61 | deal(LUSD, address(this), 1e21); 62 | 63 | // Call shouldn't revert even though the swap fails 64 | _swapRewardsToLQTYAndStake(true); 65 | } 66 | 67 | function testUrgentModeOnSwap3() public { 68 | // Destroy the pools reserves in order for the swap to fail 69 | deal(LQTY, LQTY_ETH_POOL, 0); 70 | deal(LUSD, address(this), 1e21); 71 | 72 | // Call shouldn't revert even though the swap fails 73 | _swapRewardsToLQTYAndStake(true); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/test/bridges/liquity/utils/MockPriceFeed.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IPriceFeed} from "../../../../interfaces/liquity/IPriceFeed.sol"; 6 | 7 | contract MockPriceFeed is IPriceFeed { 8 | // solhint-disable-next-line 9 | uint256 public immutable lastGoodPrice; 10 | 11 | constructor(uint256 _price) { 12 | lastGoodPrice = _price; 13 | } 14 | 15 | function fetchPrice() external override(IPriceFeed) returns (uint256) { 16 | return lastGoodPrice; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/bridges/liquity/utils/TestUtil.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 6 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 7 | import {Test} from "forge-std/Test.sol"; 8 | 9 | import {MockPriceFeed} from "./MockPriceFeed.sol"; 10 | import {IPriceFeed} from "../../../../interfaces/liquity/IPriceFeed.sol"; 11 | 12 | contract TestUtil is Test { 13 | struct Token { 14 | address addr; // ERC20 Mainnet address 15 | IERC20 erc; 16 | } 17 | 18 | address internal constant LQTY_ETH_POOL = 0xD1D5A4c0eA98971894772Dcd6D2f1dc71083C44E; // 3000 bps fee tier 19 | address internal constant USDC_ETH_POOL = 0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640; // 500 bps fee tier 20 | address internal constant LUSD_USDC_POOL = 0x4e0924d3a751bE199C426d52fb1f2337fa96f736; // 500 bps fee tier 21 | 22 | IPriceFeed internal constant LIQUITY_PRICE_FEED = IPriceFeed(0x4c517D4e2C851CA76d7eC94B805269Df0f2201De); 23 | 24 | mapping(bytes32 => Token) internal tokens; 25 | 26 | address internal rollupProcessor; 27 | 28 | // @dev This method exists on RollupProcessor.sol. It's defined here in order to be able to receive ETH like a real 29 | // rollup processor would. 30 | function receiveEthFromBridge(uint256 _interactionNonce) external payable {} 31 | 32 | function _setUpTokensAndLabels() internal { 33 | tokens["LUSD"].addr = 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0; 34 | tokens["LUSD"].erc = IERC20(tokens["LUSD"].addr); 35 | vm.label(tokens["LUSD"].addr, "LUSD"); 36 | 37 | tokens["WETH"].addr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; 38 | tokens["WETH"].erc = IERC20(tokens["WETH"].addr); 39 | vm.label(tokens["WETH"].addr, "WETH"); 40 | 41 | tokens["LQTY"].addr = 0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D; 42 | tokens["LQTY"].erc = IERC20(tokens["LQTY"].addr); 43 | vm.label(tokens["LQTY"].addr, "LQTY"); 44 | 45 | tokens["USDC"].addr = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; 46 | tokens["USDC"].erc = IERC20(tokens["USDC"].addr); 47 | vm.label(tokens["USDC"].addr, "USDC"); 48 | 49 | vm.label(LQTY_ETH_POOL, "LQTY_ETH_POOL"); 50 | vm.label(USDC_ETH_POOL, "USDC_ETH_POOL"); 51 | vm.label(LUSD_USDC_POOL, "LUSD_USDC_POOL"); 52 | } 53 | 54 | function _setLiquityPrice(uint256 _price) internal { 55 | IPriceFeed mockFeed = new MockPriceFeed(_price); 56 | vm.etch(address(LIQUITY_PRICE_FEED), address(mockFeed).code); 57 | assertEq(LIQUITY_PRICE_FEED.fetchPrice(), _price); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/bridges/uniswap/UniswapBridgeE2E.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | // Copyright 2022 Aztec. 3 | pragma solidity >=0.8.4; 4 | 5 | import {BridgeTestBase} from "./../../aztec/base/BridgeTestBase.sol"; 6 | import {AztecTypes} from "rollup-encoder/libraries/AztecTypes.sol"; 7 | 8 | import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 9 | import {ErrorLib} from "../../../bridges/base/ErrorLib.sol"; 10 | import {UniswapBridge} from "../../../bridges/uniswap/UniswapBridge.sol"; 11 | import {IQuoter} from "../../../interfaces/uniswapv3/IQuoter.sol"; 12 | 13 | contract UniswapBridgeE2ETest is BridgeTestBase { 14 | address public constant LUSD = 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0; 15 | address public constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; 16 | address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; 17 | address public constant LQTY = 0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D; 18 | address public constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; 19 | 20 | IQuoter public constant QUOTER = IQuoter(0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6); 21 | 22 | bytes private referenceSplitPath1 = 23 | abi.encodePacked(LUSD, uint24(500), USDC, uint24(3000), WETH, uint24(3000), LQTY); 24 | bytes private referenceSplitPath2 = 25 | abi.encodePacked(LUSD, uint24(500), DAI, uint24(3000), WETH, uint24(10000), LQTY); 26 | 27 | UniswapBridge private bridge; 28 | 29 | // To store the id of the swap bridge after being added 30 | uint256 private id; 31 | 32 | function setUp() public { 33 | // Deploy the bridge 34 | bridge = new UniswapBridge(address(ROLLUP_PROCESSOR)); 35 | 36 | // Use the label cheatcode to mark addresses in the traces 37 | vm.label(address(bridge), "Swap Bridge"); 38 | vm.label(address(bridge.ROUTER()), "Uni Router"); 39 | vm.label(LUSD, "LUSD"); 40 | vm.label(DAI, "DAI"); 41 | vm.label(WETH, "WETH"); 42 | vm.label(LQTY, "LQTY"); 43 | vm.label(USDC, "USDC"); 44 | 45 | // Impersonate the multi-sig to add a new bridge and assets 46 | vm.startPrank(MULTI_SIG); 47 | 48 | // List the example-bridge with a gasLimit of 1M 49 | ROLLUP_PROCESSOR.setSupportedBridge(address(bridge), 1000000); 50 | 51 | // List the assets with a gasLimit of 100k 52 | ROLLUP_PROCESSOR.setSupportedAsset(LUSD, 100000); 53 | ROLLUP_PROCESSOR.setSupportedAsset(LQTY, 100000); 54 | 55 | vm.stopPrank(); 56 | 57 | // Fetch the id of the example bridge 58 | id = ROLLUP_PROCESSOR.getSupportedBridgesLength(); 59 | 60 | // EIP-1087 optimization related mints 61 | deal(LQTY, address(bridge), 1); 62 | deal(LUSD, address(bridge), 1); 63 | deal(WETH, address(bridge), 1); 64 | } 65 | 66 | function testSwap() public { 67 | uint256 swapAmount = 1e21; // 1000 LUSD 68 | 69 | // 500 3000 3000 70 | // PATH1 LUSD -> USDC -> WETH -> LQTY 70% of input 1000110 01 010 10 001 10 71 | // 500 3000 10000 72 | // PATH2 LUSD -> DAI -> WETH -> LQTY 30% of input 0011110 01 100 10 001 11 73 | // MIN PRICE: significand 0, exponent 0 74 | // @dev Setting min price to 0 here in order to avoid issues with changing mainnet liquidity 75 | // 000000000000000000000 00000 | 0011110 01 100 10 001 11 | 1000110 01 010 10 001 10 76 | uint64 encodedPath = 0xF323C6546; 77 | 78 | { 79 | address[] memory tokensIn = new address[](1); 80 | tokensIn[0] = LUSD; 81 | 82 | address[] memory tokensOut = new address[](1); 83 | tokensOut[0] = LQTY; 84 | 85 | bridge.preApproveTokens(tokensIn, tokensOut); 86 | } 87 | 88 | // Define input and output assets 89 | AztecTypes.AztecAsset memory lusdAsset = ROLLUP_ENCODER.getRealAztecAsset(LUSD); 90 | AztecTypes.AztecAsset memory lqtyAsset = ROLLUP_ENCODER.getRealAztecAsset(LQTY); 91 | 92 | deal(LUSD, address(ROLLUP_PROCESSOR), swapAmount); 93 | 94 | // Compute quote 95 | uint256 swapAmountSplitPath1 = (swapAmount * 70) / 100; 96 | uint256 quote = QUOTER.quoteExactInput(referenceSplitPath1, swapAmountSplitPath1); 97 | quote += QUOTER.quoteExactInput(referenceSplitPath2, swapAmount - swapAmountSplitPath1); 98 | 99 | // Computes the encoded data for the specific bridge interaction 100 | uint256 bridgeCallData = 101 | ROLLUP_ENCODER.defiInteractionL2(id, lusdAsset, emptyAsset, lqtyAsset, emptyAsset, encodedPath, swapAmount); 102 | 103 | ROLLUP_ENCODER.registerEventToBeChecked( 104 | bridgeCallData, ROLLUP_ENCODER.getNextNonce(), swapAmount, quote, 0, true, "" 105 | ); 106 | ROLLUP_ENCODER.processRollup(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "lib": ["dom", "esnext", "es2017.object", "DOM.Iterable"], 5 | "outDir": "dest", 6 | "module": "NodeNext", 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "noImplicitThis": false, 10 | "esModuleInterop": true, 11 | "declaration": true, 12 | "emitDecoratorMetadata": true, 13 | "experimentalDecorators": true, 14 | "inlineSourceMap": true, 15 | "declarationMap": true, 16 | "resolveJsonModule": true, 17 | "moduleResolution": "NodeNext" 18 | }, 19 | "include": ["client", "typechain-types"] 20 | } 21 | --------------------------------------------------------------------------------