diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6d2f10d..592e1fe7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,6 +121,33 @@ jobs: echo "## Integration tests result" >> $GITHUB_STEP_SUMMARY echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + test-utils: + needs: ["lint", "build"] + runs-on: "ubuntu-latest" + steps: + - name: "Check out the repo" + uses: "actions/checkout@v3" + with: + submodules: "recursive" + + - name: "Install Foundry" + uses: "foundry-rs/foundry-toolchain@v1" + + - name: "Restore the cached build" + uses: "actions/cache/restore@v3" + with: + fail-on-cache-miss: true + key: "foundry-build-${{ github.sha }}" + path: "out-optimized" + + - name: "Run the utils tests against the optimized build" + run: "FOUNDRY_PROFILE=test-optimized forge test --match-path \"test/utils/**/*.sol\"" + + - name: "Add test summary" + run: | + echo "## Utils tests result" >> $GITHUB_STEP_SUMMARY + echo "✅ Passed" >> $GITHUB_STEP_SUMMARY + test-fork: needs: ["lint", "build"] env: diff --git a/.gitmodules b/.gitmodules index 58baa4f5..67c8ff57 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,6 +18,10 @@ branch = "release-v0" path = "lib/prb-test" url = "https://github.com/PaulRBerg/prb-test" +[submodule "lib/solady"] + branch = "main" + path = "lib/solady" + url = "https://github.com/Vectorized/solady" [submodule "lib/v2-core"] branch = "main" path = "lib/v2-core" diff --git a/lib/solady b/lib/solady new file mode 160000 index 00000000..7175c21f --- /dev/null +++ b/lib/solady @@ -0,0 +1 @@ +Subproject commit 7175c21f95255dc7711ce84cc32080a41864abd6 diff --git a/remappings.txt b/remappings.txt index 2167b583..edac14c0 100644 --- a/remappings.txt +++ b/remappings.txt @@ -8,3 +8,4 @@ forge-std/=lib/forge-std/src/ permit2/=lib/permit2/src/ permit2-test/=lib/permit2/test/ +solady/=lib/solady/src/ diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh new file mode 100755 index 00000000..97698ae4 --- /dev/null +++ b/shell/update-precompiles.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +# Pre-requisites: +# - foundry (https://getfoundry.sh) +# - jq (https://stedolan.github.io/jq) +# - sd (https://github.com/chmln/sd) + +# Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca +set -euo pipefail + +# Compile the contracts with Forge +FOUNDRY_PROFILE=optimized forge build + +# Retrieve the raw bytecodes, removing the "0x" prefix +archive=$(cat out-optimized/SablierV2Archive.sol/SablierV2Archive.json | jq -r '.bytecode.object' | cut -c 3-) +proxy_plugin=$(cat out-optimized/SablierV2ProxyPlugin.sol/SablierV2ProxyPlugin.json | jq -r '.bytecode.object' | cut -c 3-) +proxy_target=$(cat out-optimized/SablierV2ProxyTarget.sol/SablierV2ProxyTarget.json | jq -r '.bytecode.object' | cut -c 3-) + +precompiles_path="test/utils/Precompiles.sol" +if [ ! -f $precompiles_path ]; then + echo "Precompiles file does not exist" + exit 1 +fi + +# Replace the current bytecodes +sd "(BYTECODE_ARCHIVE =)[^;]+;" "\$1 hex\"$archive\";" $precompiles_path +sd "(BYTECODE_PROXY_PLUGIN =)[^;]+;" "\$1 hex\"$proxy_plugin\";" $precompiles_path +sd "(BYTECODE_PROXY_TARGET =)[^;]+;" "\$1 hex\"$proxy_target\";" $precompiles_path + +# Reformat the code with Forge +forge fmt $precompiles_path diff --git a/test/Base.t.sol b/test/Base.t.sol index 79dbb4fe..52259bb3 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.19 <0.9.0; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import { IPRBProxy } from "@prb/proxy/interfaces/IPRBProxy.sol"; @@ -58,6 +59,10 @@ abstract contract Base_Test is Assertions, Events, StdCheats, V2CoreUtils { //////////////////////////////////////////////////////////////////////////*/ function setUp() public virtual { + // Deploy the default test asset. + asset = new ERC20("DAI Stablecoin", "DAI"); + + // Create users for testing. users.alice = createUser("Alice"); users.admin = createUser("Admin"); users.broker = createUser("Broker"); @@ -84,8 +89,8 @@ abstract contract Base_Test is Assertions, Events, StdCheats, V2CoreUtils { target = new SablierV2ProxyTarget(permit2); } else { archive = deployPrecompiledArchive(users.admin.addr); - plugin = deployPrecompiledPlugin(archive); - target = deployPrecompiledTarget(permit2); + plugin = deployPrecompiledProxyPlugin(archive); + target = deployPrecompiledProxyTarget(permit2); } } @@ -97,14 +102,14 @@ abstract contract Base_Test is Assertions, Events, StdCheats, V2CoreUtils { } /// @dev Deploys {SablierV2ProxyPlugin} from a source precompiled with `--via-ir`. - function deployPrecompiledPlugin(ISablierV2Archive archive_) internal returns (ISablierV2ProxyPlugin) { + function deployPrecompiledProxyPlugin(ISablierV2Archive archive_) internal returns (ISablierV2ProxyPlugin) { return ISablierV2ProxyPlugin( deployCode("out-optimized/SablierV2ProxyPlugin.sol/SablierV2ProxyPlugin.json", abi.encode(archive_)) ); } /// @dev Deploys {SablierV2ProxyTarget} from a source precompiled with `--via-ir`. - function deployPrecompiledTarget(IAllowanceTransfer permit2_) internal returns (ISablierV2ProxyTarget) { + function deployPrecompiledProxyTarget(IAllowanceTransfer permit2_) internal returns (ISablierV2ProxyTarget) { return ISablierV2ProxyTarget( deployCode("out-optimized/SablierV2ProxyTarget.sol/SablierV2ProxyTarget.json", abi.encode(permit2_)) ); diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index 5840844f..35613c5c 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.19 <0.9.0; -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IAllowanceTransfer } from "permit2/interfaces/IAllowanceTransfer.sol"; import { Precompiles as PRBProxyPrecompiles } from "@prb/proxy-test/utils/Precompiles.sol"; @@ -20,9 +19,6 @@ abstract contract Integration_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ function setUp() public virtual override { - // Deploy the default test asset. - asset = new ERC20("DAI Stablecoin", "DAI"); - // Set up the base test contract. Base_Test.setUp(); diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol new file mode 100644 index 00000000..f604262a --- /dev/null +++ b/test/utils/Precompiles.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable max-line-length,no-inline-assembly,reason-string +pragma solidity >=0.8.19; + +import { IAllowanceTransfer } from "permit2/interfaces/IAllowanceTransfer.sol"; + +import { ISablierV2Archive } from "../../src/interfaces/ISablierV2Archive.sol"; +import { ISablierV2ProxyPlugin } from "../../src/interfaces/ISablierV2ProxyPlugin.sol"; +import { ISablierV2ProxyTarget } from "../../src/interfaces/ISablierV2ProxyTarget.sol"; + +contract Precompiles { + /*////////////////////////////////////////////////////////////////////////// + BYTECODES + //////////////////////////////////////////////////////////////////////////*/ + + bytes public constant BYTECODE_ARCHIVE = + hex"60803461007457601f61047538819003918201601f19168301916001600160401b038311848410176100795780849260209460405283398101031261007457516001600160a01b0381169081900361007457600080546001600160a01b0319169190911790556040516103e590816100908239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060408181526004918236101561001657600080fd5b600092833560e01c91826375829def146102e657508163bb032a661461022b578163bde3672d1461011c578163f794062e146100af575063f851a4401461005c57600080fd5b346100ab57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100ab5773ffffffffffffffffffffffffffffffffffffffff60209254169051908152f35b5080fd5b9050346101185760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610118573573ffffffffffffffffffffffffffffffffffffffff811680910361011857818360ff92602095526001855220541690519015158152f35b8280fd5b919050346101185760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101185781359173ffffffffffffffffffffffffffffffffffffffff808416809403610227578454163381036101d4575050818352600160205282207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055337fb9835cd339eaf06fa84e93033cbaef0efbd524b078bf101a5a73040c8e1a3a6b8380a380f35b82517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169181019182523360208301529081906040010390fd5b8480fd5b919050346101185760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101185781359173ffffffffffffffffffffffffffffffffffffffff808416809403610227578454163381036101d45750508183526001602052822060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055337fb9b4b5889ee1c30795c18ef5221a2a05de69d5655670bd5db987bbecc1b9646b8380a380f35b8491346101185760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101185780359173ffffffffffffffffffffffffffffffffffffffff91828416809403610227578454928316338103610397575050507fffffffffffffffffffffffff00000000000000000000000000000000000000001681178255337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808380a380f35b7fc6cce6a400000000000000000000000000000000000000000000000000000000835273ffffffffffffffffffffffffffffffffffffffff1690820190815233602082015281906040010390fd"; + bytes public constant BYTECODE_PROXY_PLUGIN = + hex"60c03461007d57601f61096f38819003918201601f19168301916001600160401b038311848410176100825780849260209460405283398101031261007d57516001600160a01b038116810361007d573060805260a0526040516108d6908161009982396080518160c6015260a05181818161012201526106b70152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060408181526004908136101561001657600080fd5b600092833560e01c90816302a214601461066d575080636aeb459414610571576372eba2031461004557600080fd5b3461056d5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261056d578135602491823573ffffffffffffffffffffffffffffffffffffffff908181160361056957604435926fffffffffffffffffffffffffffffffff808516809503610485576064359081160361056557817f000000000000000000000000000000000000000000000000000000000000000016301461053d578251937ff794062e0000000000000000000000000000000000000000000000000000000085523387860152602094858188818c887f0000000000000000000000000000000000000000000000000000000000000000165af190811561044a578991610510575b50156104e25783517fb971302a000000000000000000000000000000000000000000000000000000008152828882015285818881335afa90811561044a5789916104c5575b50833091160361049a578351917feac8f5b80000000000000000000000000000000000000000000000000000000083528783015284828781335afa918215610490578892610454575b5083517f8da5cb5b00000000000000000000000000000000000000000000000000000000815285818981305afa90811561044a57899161041d575b5084519184878401927fa9059cbb0000000000000000000000000000000000000000000000000000000084521688840152604483015260448252608082019367ffffffffffffffff93838610858711176103f257858752169189918291610281876106df565b8887527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656460a0820152519082855af1903d156103e3573d9283116103b857906103079392918551926102fa887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018561072a565b83523d8a8885013e6107b4565b8051908382159283156103a0575b50505015610321578480f35b517f08c379a000000000000000000000000000000000000000000000000000000000815292830152602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608490fd5b6103b0935082018101910161076b565b388381610315565b868960418a7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b906103079392506060916107b4565b888b60418c7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b61043d9150863d8811610443575b610435818361072a565b810190610788565b3861021b565b503d61042b565b85513d8b823e3d90fd5b9091508481813d8311610489575b61046c818361072a565b81010312610485575182811681036104855790386101e0565b8780fd5b503d610462565b84513d8a823e3d90fd5b85886001897f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b6104dc9150863d881161044357610435818361072a565b38610197565b83517f09bd4d6800000000000000000000000000000000000000000000000000000000815233818901528690fd5b6105309150863d8811610536575b610528818361072a565b81019061076b565b38610152565b503d61051e565b8583517fbbff6135000000000000000000000000000000000000000000000000000000008152fd5b8680fd5b8580fd5b8280fd5b50903461056d57827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261056d5781516105ac816106df565b6001938482526020908183019382368637835115610641575091907f72eba20300000000000000000000000000000000000000000000000000000000849694528451948186019282875251809352850195925b82811061060c5785870386f35b83517fffffffff00000000000000000000000000000000000000000000000000000000168752958101959281019284016105ff565b9060326024927f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b8490346106db57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106db5760209073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b5080fd5b6040810190811067ffffffffffffffff8211176106fb57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176106fb57604052565b90816020910312610783575180151581036107835790565b600080fd5b90816020910312610783575173ffffffffffffffffffffffffffffffffffffffff811681036107835790565b9192901561082f57508151156107c8575090565b3b156107d15790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156108425750805190602001fd5b604051907f08c379a000000000000000000000000000000000000000000000000000000000825281602080600483015282519283602484015260005b8481106108bf575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604480968601015201168101030190fd5b81810183015186820160440152859350820161087e56"; + bytes public constant BYTECODE_PROXY_TARGET = + hex"60c0346200007d57601f620042a838819003918201601f19168301916001600160401b0383118484101762000082578084926020946040528339810103126200007d57516001600160a01b03811681036200007d573060805260a05260405161420f9081620000998239608051816141bd015260a05181613fb70152f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816310fad8c81461281b575080631d165efc1461268f57806339532c191461244057806351c9b6f1146123d957806361ea5802146120fe5780636a09d49a1461201a578063868699c514611e8d57806386f2891e14611e155780638922211914611dae5780638ad7937414611b7357806390e2cd79146119b657806398590ef9146117c15780639dc29fac14611746578063a3143b76146116cd578063a4af60d214611357578063ad26c0fb146112cc578063b956b45f14611206578063c00b86a514610f26578063c0cb6a4014610d51578063c426f89c14610b03578063ec5b900f14610954578063f1630612146107bf578063f65e5d66146103ce5763fe5cacde1461012957600080fd5b346103c75760031960a0813601126103ca57610143612a0e565b9160243591610150612a24565b906064359267ffffffffffffffff918285116103ca576101008186360301126103ca576084359283116103ca5760e09083360301126103c7576101916141b3565b6101996141b3565b6001600160a01b0380961690604051957feac8f5b80000000000000000000000000000000000000000000000000000000087528060048801526020978888602481875afa9788156103bc578398610384575b50871690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a86602481875afa95861561037957859661034a575b50813b156103465784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1801561033b578a9291859161031e575b505060246040518094819382523060048301525afa91821561031257916102dc575b50946102b86102c7926102d497612e6b565b906102c1613c99565b90612ea7565b6004019160040190613665565b604051908152f35b9590508686813d831161030b575b6102f48183612aee565b810103126103065794516102b86102a6565b600080fd5b503d6102ea565b604051903d90823e3d90fd5b61032a91929350612aa2565b6103375788908338610284565b8280fd5b6040513d86823e3d90fd5b8480fd5b9095508a81813d8311610372575b6103628183612aee565b8101031261030657519438610234565b503d610358565b6040513d87823e3d90fd5b9097508881813d83116103b5575b61039c8183612aee565b81010312610337575187811681036103375796386101eb565b503d610392565b6040513d85823e3d90fd5b80fd5b5080fd5b50346103c7576003196101c0813601126103ca576103ea612a0e565b906024908135926103f9612a24565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126107b7576101a4359267ffffffffffffffff84116107bb5760e09084360301126107b75761044c6141b3565b6104546141b3565b6001600160a01b03809216604051907feac8f5b800000000000000000000000000000000000000000000000000000000825286600483015260209687838881855afa92831561070f57899361077b575b508885841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528b868c81885afa95861561033b578496610748575b50813b156107445783918b839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578b9361071a575b5050886040518094819382523060048301525afa90811561070f578596979899916106d7575b5061057092916102b891612e6b565b6105786141b3565b169160c435828116918282036103065760a435916fffffffffffffffffffffffffffffffff831680930361030657826105b5926004019187613f9f565b604051947f4bc78b7300000000000000000000000000000000000000000000000000000000865260643584811680910361030657600487015260843590848216809203610306578601526044850152606484015260e4358015158091036103065760848401526101049081359064ffffffffff918281168091036103065760a48601526101249283358381168091036103065760c48701526101449283359081168091036103065760e4870152610164359182168092036103065786948694859360009385015261018435908401525af19081156106cb5760009161069e575b50604051908152f35b908282813d83116106c4575b6106b48183612aee565b810103126103c757505138610695565b503d6106aa565b6040513d6000823e3d90fd5b9450909190508784813d8111610708575b6106f28183612aee565b8101031261030657925184939190610570610561565b503d6106e8565b6040513d8b823e3d90fd5b61072691929350612aa2565b6107335788908a3861053b565b8980fd5b50604051903d90823e3d90fd5b8380fd5b8c809297508195503d8311610774575b6107628183612aee565b81010312610306578b925194386104ee565b503d610758565b9092508781813d83116107b0575b6107938183612aee565b810103126107ac575184811681036107ac5791386104a4565b8880fd5b503d610789565b8580fd5b8680fd5b50346103c75760406003193601126103c75767ffffffffffffffff600435818111610337576107f2903690600401612ca9565b91906024358281116103465761080c903690600401612ca9565b9290916108176141b3565b841561092a57856108288585613bcb565b92815b878110610841578261083e888888613d18565b80f35b61084c818986612dba565b356001600160a01b03811680910361074457610869828a87612dba565b60209081810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156107bb5701908135918583116107bb5701908060051b360382136107b757823b156107b7576108fa928692836040518096819582947f8659c27000000000000000000000000000000000000000000000000000000000845260048401612e29565b03925af190811561033b578491610916575b505060010161082b565b61091f90612aa2565b61033757823861090c565b60046040517f71594532000000000000000000000000000000000000000000000000000000008152fd5b50600319906040823601126103c75761096b612a0e565b916024359067ffffffffffffffff9081831161074457610100908336030112610337576040519061099b82612a3a565b6109a783600401612b27565b82526109b560248401612b9c565b94602095868401526109c960448501612b27565b60408401526109da60648501612b5a565b91606084019283526109ee60848601612b27565b9460808501958652610a033660a48301612bbb565b60a086015260e48101359182116107bb5701366023820112156107b75792610a88610abd93879693610a408a973690602460048201359101612c17565b60c0850152610a4d6141b3565b6fffffffffffffffffffffffffffffffff9081341683526001600160a01b038091610a7a82895116613df7565b169551169151169084613a07565b6040519485809481937fbf061d0a00000000000000000000000000000000000000000000000000000000835260048301613408565b03925af19182156103125791610ad65750604051908152f35b90508181813d8311610afc575b610aed8183612aee565b81010312610306575138610695565b503d610ae3565b50346103c75760031960a0813601126103ca57610b1e612a0e565b9160243591610b2b612a24565b906064359267ffffffffffffffff918285116103ca576101208186360301126103ca576084359283116103ca5760e09083360301126103c757610b6c6141b3565b610b746141b3565b6001600160a01b0380961690604051957feac8f5b80000000000000000000000000000000000000000000000000000000087528060048801526020978888602481875afa9788156103bc578398610d19575b50871690604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528a86602481875afa958615610379578596610cea575b50813b156103465784916024839260405194859384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1801561033b578a92918591610cd1575b505060246040518094819382523060048301525afa9182156103125791610ca0575b50946102b8610c93926102d497612e6b565b6004019160040190613895565b9590508686813d8311610cca575b610cb88183612aee565b810103126103065794516102b8610c81565b503d610cae565b610cdd91929350612aa2565b6103375788908338610c5f565b9095508a81813d8311610d12575b610d028183612aee565b8101031261030657519438610c0f565b503d610cf8565b9097508881813d8311610d4a575b610d318183612aee565b8101031261033757518781168103610337579638610bc6565b503d610d27565b50346103c75760031990610180823601126103c757610d6e612a0e565b906101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c757610164359267ffffffffffffffff84116103ca5760e09084360301126103c75750610dc36141b3565b6001600160a01b03809116608435928284169081850361030657606435946fffffffffffffffffffffffffffffffff86168096036103065785610e0a926004019185613f9f565b604051937f4bc78b730000000000000000000000000000000000000000000000000000000085526024358481168091036103065760048601526044358481168091036103065760248601526044850152606484015260a43580151580910361030657608484015260c4359164ffffffffff928381168091036103065760a485015260e4358381168091036103065760c48501526101049283359081168091036103065760e485015261012490813590811680910361030657600085938492602096840152610144938435908401525af19081156106cb57600091610ef4575b602082604051908152f35b6020813d8211610f1e575b81610f0c60209383612aee565b810103126103ca575190506020610ee9565b3d9150610eff565b50346103c7576080600319818136011261033757610f42612a0e565b610f4a612b11565b916044359067ffffffffffffffff948583116107bb57366023840112156107bb57826004013591868311611202576024840193602436918560081b010111611202576064359687116112025760e09087360301126107bb57610faa6141b3565b811561092a5790939086805b8681106111bf5750610fd9906001600160a01b0380961697600401908489613f9f565b610fe28561319f565b9584889316925b8681106110025760405180610ffe8a82612d4b565b0390f35b60c0908682611012838b8a613172565b018960609481898b8789611027828685613172565b01611031906131d0565b9361103b92613172565b978c6020978861104c8b8985613172565b01611056906131dd565b918a611063818a84613172565b61106c906131dd565b9861107692613172565b60400161108290613182565b9181604051986110918a612a3a565b16885216888701526fffffffffffffffffffffffffffffffff1660408601528401521515888301528536037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff800160401361030657611123849361115c97604051906110fb82612ad2565b6111068c8201612ba9565b825261111560a0809201612ba9565b878301528501523690612bbb565b908201528c60405180809781947f1b4103a9000000000000000000000000000000000000000000000000000000008352600483016131f1565b0391885af19081156111b4578b91611185575b506001925061117e828b61328a565b5201610fe9565b905082813d83116111ad575b61119b8183612aee565b8101031261030657600191513861116f565b503d611191565b6040513d8d823e3d90fd5b906001600160a01b036001916fffffffffffffffffffffffffffffffff6111f560406111ef878d8c9e9b9e613172565b01613182565b1601169101959295610fb6565b8780fd5b50346103c75760806003193601126103c75780611221612a0e565b611229612a24565b611231612b3b565b9161123a6141b3565b6001600160a01b03809116803b15610346578492836064926fffffffffffffffffffffffffffffffff60405197889687957ffdd46d6000000000000000000000000000000000000000000000000000000000875260243560048801521660248601521660448401525af180156112c1576112b15750f35b6112ba90612aa2565b6103c75780f35b6040513d84823e3d90fd5b50346103c757806001600160a01b036112e436612d86565b9290916112ef6141b3565b1691823b15611352576040517fc156a11d00000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b031660248201529082908290818381604481015b03925af180156112c1576112b15750f35b505050fd5b50346103c7576003196101a0813601126103ca57611373612a0e565b602490813592611381612a24565b6101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c3601126107b757610184359167ffffffffffffffff83116107bb5760e09083360301126107b7576113d46141b3565b6113dc6141b3565b6001600160a01b03809316604051907feac8f5b800000000000000000000000000000000000000000000000000000000825286600483015260209687838881855afa92831561070f578993611695575b508886841691604051937f70a0823100000000000000000000000000000000000000000000000000000000918286523060048701528b868c81885afa95861561033b578496611662575b50813b156107445783918b839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578b93611649575b5050886040518094819382523060048301525afa90811561070f578697989996959691611611575b506114fa92916102b891612e6b565b6115026141b3565b169060c435838116918282036103065760a435916fffffffffffffffffffffffffffffffff8316809303610306578261153f926004019186613f9f565b604051947f1b4103a900000000000000000000000000000000000000000000000000000000865260643585811680910361030657600487015260843590858216809203610306578601526044850152606484015260e43580151580910361030657608484015264ffffffffff6101048035828116908190036103065760a48601526101249182359081168091036103065760c48601526101443593841680940361030657600085938492889660e485015261016435908401525af19081156106cb5760009161069e5750604051908152f35b9450909190508784813d8111611642575b61162c8183612aee565b81010312610306579251859391906114fa6114eb565b503d611622565b61165591929350612aa2565b6107335788908a386114c3565b8c809297508195503d831161168e575b61167c8183612aee565b81010312610306578b92519438611476565b503d611672565b9092508781813d83116116c6575b6116ad8183612aee565b810103126107ac575185811681036107ac57913861142c565b503d6116a3565b50346103c757806001600160a01b036116e536612d86565b9290916116f06141b3565b1691823b15611352576040517fea5ead1900000000000000000000000000000000000000000000000000000000815260048101929092526001600160a01b03166024820152908290829081838160448101611341565b50346103c75760406003193601126103c757806001600160a01b03611769612a0e565b6117716141b3565b16803b156117be578180916024604051809481937f42966c68000000000000000000000000000000000000000000000000000000008352833560048401525af180156112c1576112b15750f35b50fd5b50346103c75760406003193601126103c7576117db612a0e565b6024356117e66141b3565b6001600160a01b0380921691604051917feac8f5b8000000000000000000000000000000000000000000000000000000008352806004840152846020928385602481895afa9485156112c157829561197e575b50841691604051957f70a0823100000000000000000000000000000000000000000000000000000000918288523060048901528588602481885afa97881561033b57849861194b575b50813b156107445783916024839260405196879384927f40e58ee500000000000000000000000000000000000000000000000000000000845260048401525af1928315610737578593611932575b505060246040518094819382523060048301525afa918215610379578592611902575b505061083e926102b891612e6b565b90809250813d831161192b575b6119198183612aee565b810103126103065751826102b86118f3565b503d61190f565b61193e91929350612aa2565b6107b757829086386118d0565b86809299508195503d8311611977575b6119658183612aee565b81010312610306578792519638611882565b503d61195b565b9094508381813d83116119af575b6119968183612aee565b810103126103ca575184811681036103ca579338611839565b503d61198c565b506101406003193601126103c7576119cc612a0e565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c75760405191611a0583612a3a565b611a0d612b11565b8352611a17612a24565b9260209384820152611a27612b3b565b9060408101918252611a37612b77565b60608201908152611a46612b8d565b608083015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c36011261030657604051611a8181612ad2565b64ffffffffff60c435818116810361030657825260e4359081168103610306578782015260a083015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefc3601126103065760405191611ae183612ad2565b610104356001600160a01b03948582168203610306578796899686611b3e94610abd9852610124358982015260c0860152611b1a6141b3565b806fffffffffffffffffffffffffffffffff928334168552610a7a82895116613df7565b6040519485809481937f1b4103a9000000000000000000000000000000000000000000000000000000008352600483016131f1565b50346103c757611b8236612cda565b611b8e949193946141b3565b831561092a578591865b858110611d775750906001600160a01b03611bb69216928684613f9f565b611bbf8361319f565b93855b848110611bd75760405180610ffe8882612d4b565b60809081611be6828888613374565b018587611bf4848284613374565b602001611c00906131d0565b92611c0c858385613374565b604001611c18906131dd565b9585611c25818587613374565b958160c097888101611c36916133b4565b96611c42929198613374565b611c4b906131dd565b988d8d6060948592611c5c92613374565b01611c6690613182565b916040519a611c748c612a3a565b6001600160a01b03168b52151560208b01526001600160a01b031660408a01526fffffffffffffffffffffffffffffffff16908801526001600160a01b0388169087015236611cc291612bbb565b60a08601523690611cd292612c17565b90830152836040518080947fbf061d0a0000000000000000000000000000000000000000000000000000000082526004820190611d0e91613408565b03818b5a94602095f18015611d6c578890611d39575b60019250611d32828961328a565b5201611bc2565b506020823d602011611d64575b81611d5360209383612aee565b810103126103065760019151611d24565b3d9150611d46565b6040513d8a823e3d90fd5b926001600160a01b036001916fffffffffffffffffffffffffffffffff611da460606111ef898c8c613374565b1601169301611b98565b50346103c7576003196060813601126103ca57611dc9612a0e565b906024359267ffffffffffffffff918285116103ca576101008186360301126103ca576044359283116103ca5760e09083360301126103c75760206102d4600480850190870186613665565b50346103c75760406003193601126103c757806001600160a01b03611e38612a0e565b611e406141b3565b16803b156117be578180916024604051809481937f7de6b1db000000000000000000000000000000000000000000000000000000008352833560048401525af180156112c1576112b15750f35b50346103c75760031990610160823601126103c757611eaa612a0e565b906101207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103c757610144359267ffffffffffffffff84116103ca5760e09084360301126103c75750611eff6141b3565b6001600160a01b0380911690608435928184169081850361030657606435946fffffffffffffffffffffffffffffffff86168096036103065785611f47926004019186613f9f565b604051937f1b4103a90000000000000000000000000000000000000000000000000000000085526024358381168091036103065760048601526044358381168091036103065760248601526044850152606484015260a43580151580910361030657608484015260c43564ffffffffff908181168091036103065760a485015260e4359081168091036103065760c4840152610104803591821680920361030657836000602094829460e4840152610124938435908401525af19081156106cb57600091610ef457602082604051908152f35b50346103c75760606003193601126103c757612034612a0e565b9067ffffffffffffffff60243581811161033757612056903690600401612ca9565b916044359081116107445761206f903690600401612ca9565b906120786141b3565b6001600160a01b0361208a8585613bcb565b961690813b156107b7579185916120d193836040518096819582947f8659c27000000000000000000000000000000000000000000000000000000000845260048401612e29565b03925af1801561033b576120eb575b5061083e9293613d18565b926120f861083e94612aa2565b926120e0565b50346103c7576080906003199082823601126103c75761211c612a0e565b90612125612b11565b916044359367ffffffffffffffff91828611610744573660238701121561074457856004013591838311610346576024870196602436916101208602010111610346576064359384116103465760e0908436030112610744576121866141b3565b811561092a5793959383805b83811061239c57506121b5906001600160a01b0380931694600401908986613f9f565b6121be8261319f565b9581859816975b8381106121da5760405180610ffe8a82612d4b565b88816121e781878661329e565b60e001606090816121f9848a8961329e565b01612203906131d0565b9161220f848a8961329e565b926020958a8a818b898b61222482858561329e565b0161222e906131dd565b946122389261329e565b612241906131dd565b9861224c918d61329e565b60400161225890613182565b9181604051996122678b612a3a565b16895216888801526fffffffffffffffffffffffffffffffff1660408701528286015215158c8501528236037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8001126107335791839161230b612342948d6122dc604051916122d583612ab6565b8501612ba9565b815260a06122eb818601612ba9565b878301526122fc60c0809601612ba9565b60408301528501523690612bbb565b90820152604051809381927f4bc78b73000000000000000000000000000000000000000000000000000000008352600483016132af565b03818b8b5af1918215611d6c57889261236d575b505090600191612366828b61328a565b52016121c5565b90809250813d8311612395575b6123848183612aee565b810103126107bb5751600138612356565b503d61237a565b906001600160a01b036001916fffffffffffffffffffffffffffffffff6123cc60406111ef879c9e9c8a8f61329e565b1601169101979597612192565b50346103c7576003196060813601126103ca576123f4612a0e565b906024359267ffffffffffffffff918285116103ca576101208186360301126103ca576044359283116103ca5760e09083360301126103c75760206102d4600480850190870186613895565b50346103c75761244f36612cda565b61245c94919293946141b3565b821561092a5785865b84811061265857509061248291866001600160a01b038516613f9f565b61248b8261319f565b93855b8381106124a35760405180610ffe8882612d4b565b60a06124b082868861350e565b01906124c860406124c283888a61350e565b016131d0565b866124df60606124d9858a8561350e565b016131dd565b916124f86124ee858a8561350e565b60e08101906133b4565b6020612518878c61251261250d83838b61350e565b6131dd565b9761350e565b01359464ffffffffff86168603612654576125f0976fffffffffffffffffffffffffffffffff61257b966001600160a01b038f948f9864ffffffffff60209c848f60806111ef6125b89f92612570936125ac9e61350e565b966040519e8f612a85565b168d52168c8c0152151560408b01521660608901521660808701526001600160a01b038a1660a08701523690612bbb565b60c08501523691612c17565b60e0820152604051809481927f21714be10000000000000000000000000000000000000000000000000000000083526004830161354e565b03818b6001600160a01b0389165af18015611d6c578890612621575b6001925061261a828961328a565b520161248e565b506020823d60201161264c575b8161263b60209383612aee565b81010312611202576001915161260c565b3d915061262e565b8d80fd5b906001600160a01b036001916fffffffffffffffffffffffffffffffff61268560806111ef878b8d61350e565b1601169101612465565b50600319906040823601126103c7576126a6612a0e565b916024359067ffffffffffffffff908183116107445761012090833603011261033757604051906126d682612a85565b6126e283600401612b27565b82526126f060248401612ba9565b946020958684015261270460448501612b9c565b604084015261271560648501612b27565b606084015261272660848501612b5a565b916080840192835261273a60a48601612b27565b9460a0850195865261274f3660c48301612bbb565b60c08601526101048101359182116107bb5701366023820112156107b7579261279a6127cf9387969361278d8a973690602460048201359101612c17565b60e0850152610a4d6141b3565b6040519485809481937f21714be10000000000000000000000000000000000000000000000000000000083526004830161354e565b03925af19182156103125780926127eb575b5050604051908152f35b9091508282813d8311612814575b6128038183612aee565b810103126103c757505138806127e1565b503d6127f9565b826101606003193601126103c757612831612a0e565b6101407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc3601126103ca5761286583612a3a565b61286d612b11565b8352612877612a24565b9260209384820152612887612b3b565b60408201908152612896612b77565b92606083019384526128a6612b8d565b608084015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c360112610346576040516128e181612ab6565b64ffffffffff60c435818116810361120257825260e435818116810361120257888301526101043590811681036107bb57604082015260a084015260407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedc3601126103465760405161295281612ad2565b6001600160a01b03906101243582811681036112025793879693899693836129c39761298e9552610144358982015260c0860152611b1a6141b3565b6040519485809481937f4bc78b73000000000000000000000000000000000000000000000000000000008352600483016132af565b03925af19182156103125780926129de575050604051908152f35b9091508282813d8311612a07575b6129f68183612aee565b810103126103c757505182806127e1565b503d6129ec565b600435906001600160a01b038216820361030657565b604435906001600160a01b038216820361030657565b60e0810190811067ffffffffffffffff821117612a5657604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610100810190811067ffffffffffffffff821117612a5657604052565b67ffffffffffffffff8111612a5657604052565b6060810190811067ffffffffffffffff821117612a5657604052565b6040810190811067ffffffffffffffff821117612a5657604052565b90601f601f19910116810190811067ffffffffffffffff821117612a5657604052565b602435906001600160a01b038216820361030657565b35906001600160a01b038216820361030657565b606435906fffffffffffffffffffffffffffffffff8216820361030657565b35906fffffffffffffffffffffffffffffffff8216820361030657565b608435906001600160a01b038216820361030657565b60a43590811515820361030657565b3590811515820361030657565b359064ffffffffff8216820361030657565b919082604091031261030657604051612bd381612ad2565b6020808294612be181612b27565b84520135910152565b67ffffffffffffffff8111612a565760051b60200190565b359067ffffffffffffffff8216820361030657565b929192612c2382612bea565b604094612c3286519283612aee565b8195848352602080930191606080960285019481861161030657925b858410612c5e5750505050505050565b8684830312610306578487918451612c7581612ab6565b612c7e87612b5a565b8152612c8b838801612c02565b83820152612c9a868801612ba9565b86820152815201930192612c4e565b9181601f840112156103065782359167ffffffffffffffff8311610306576020808501948460051b01011161030657565b9060031991608083820112610306576001600160a01b0392600435848116810361030657936024359081168103610306579267ffffffffffffffff6044358181116103065784612d2c91600401612ca9565b94909493606435928311610306578260e0920301126103065760040190565b6020908160408183019282815285518094520193019160005b828110612d72575050505090565b835185529381019392810192600101612d64565b6003196060910112610306576001600160a01b03600435818116810361030657916024359160443590811681036103065790565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610306570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b602081528260208201527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83116103065760409260051b809284830137010190565b91908203918211612e7857565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152612f0191612efc606483612aee565b612f1b565b565b90816020910312610306575180151581036103065790565b604051612f79916001600160a01b0316612f3482612ad2565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af1612f7361302e565b9161306e565b805190828215928315613016575b50505015612f925750565b608490604051907f08c379a00000000000000000000000000000000000000000000000000000000082526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152fd5b6130269350820181019101612f03565b388281612f87565b3d15613069573d9067ffffffffffffffff8211612a56576040519161305d6020601f19601f8401160184612aee565b82523d6000602084013e565b606090565b919290156130e95750815115613082575090565b3b1561308b5790565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152fd5b8251909150156130fc5750805190602001fd5b604051907f08c379a000000000000000000000000000000000000000000000000000000000825281602080600483015282519283602484015260005b84811061315b57505050601f19601f836000604480968601015201168101030190fd5b818101830151868201604401528593508201613138565b9190811015612dfa5760081b0190565b356fffffffffffffffffffffffffffffffff811681036103065790565b906131a982612bea565b6131b66040519182612aee565b828152601f196131c68294612bea565b0190602036910137565b3580151581036103065790565b356001600160a01b03811681036103065790565b612f019092919260e060c06101208301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151602064ffffffffff918281511660a0880152015116828501520151910190602080916001600160a01b0381511684520151910152565b8051821015612dfa5760209160051b010190565b9190811015612dfa57610120020190565b612f019092919261010060c06101408301956001600160a01b038082511685528060208301511660208601526fffffffffffffffffffffffffffffffff6040830151166040860152606082015116606085015260808101511515608085015260a0810151604064ffffffffff918281511660a0880152826020820151168588015201511660e08501520151910190602080916001600160a01b0381511684520151910152565b602080916001600160a01b0361336a82612b27565b1684520135910152565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2181360301821215610306570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610306570180359067ffffffffffffffff82116103065760200191606082023603831361030657565b9060208083526101208301908061014060c06001600160a01b0395868151168489015283810151151560408901528660408201511696606097888a01526fffffffffffffffffffffffffffffffff888301511660808a015260808201511660a089015261348f60a0820151838a0190602080916001600160a01b0381511684520151910152565b015195610100808201528651809552019401926000905b8382106134b557505050505090565b90919293948382826135016001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01960194939201906134a6565b9190811015612dfa5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0181360301821215610306570190565b9060208083526101408301908061016060e06001600160a01b0395868151168489015264ffffffffff848201511660408901526040810151151596606097888a015280888301511660808a01526fffffffffffffffffffffffffffffffff60808301511660a08a015260a08201511660c08901526135e660c0820151838a0190602080916001600160a01b0381511684520151910152565b015195610120808201528651809552019401926000905b83821061360c57505050505090565b90919293948382826136586001948a5164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01960194939201906135fd565b909161366f6141b3565b60808301916001600160a01b03908116613688846131dd565b9260606136b6818801926fffffffffffffffffffffffffffffffff96876136ae86613182565b169086613f9f565b61375e6040519788957fbf061d0a00000000000000000000000000000000000000000000000000000000875261373e6020998a998a60048b01526137336101248b01988561370388612b27565b1660248d01526137148d8801612b9c565b151560448d01528561372860408901612b27565b1660648d0152612b5a565b1660848a0152612b27565b1660a487015261375460c4870160a08301613355565b60e08101906137f1565b809193610100610104880152526101448501929160005b8281106137ca5750505050600083809203925af19081156106cb5760009161379e575b50905090565b82813d83116137c3575b6137b28183612aee565b810103126103c75750518038613798565b503d6137a8565b92955060019194965080846137e0829689613844565b019501910192879492879694613775565b90357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561030657016020813591019167ffffffffffffffff821161030657606082023603831361030657565b64ffffffffff61388f604080936fffffffffffffffffffffffffffffffff61386b82612b5a565b16865267ffffffffffffffff61388360208301612c02565b16602087015201612ba9565b16910152565b9161398091926138a36141b3565b6001600160a01b0380911660a08501926138bc846131dd565b906138e160808801916fffffffffffffffffffffffffffffffff93846136ae85613182565b6139a16040519788957f21714be100000000000000000000000000000000000000000000000000000000875260209889988960048a01526101448901968361392886612b27565b1660248b015264ffffffffff61393f8c8701612ba9565b1660448b015261395160408601612b9c565b151560648b01526139756060978561396a8a8901612b27565b1660848d0152612b5a565b1660a48a0152612b27565b1660c487015261399660e4870160c08301613355565b6101008101906137f1565b809193610120610124880152526101648501929160005b8281106139e05750505050600083809203925af19081156106cb5760009161379e5750905090565b92955060019194965080846139f6829689613844565b0195019101928794928796946139b8565b91906001600160a01b039283821690604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701528116918260248701526020958681604481855afa80156106cb578691600091613b8b575b5010613a76575b505050505050565b60008060405196613ada88613acc8b8201937f095ea7b3000000000000000000000000000000000000000000000000000000009889865260248401602090939291936001600160a01b0360408201951681520152565b03601f1981018a5289612aee565b87519082855af190613aea61302e565b82613b58575b5081613b4d575b5015613b04575b80613a6e565b60405194850152602484015260006044840152604483526080830183811067ffffffffffffffff821117612a5657613b4393612efc9160405282612f1b565b3880808080613afe565b90503b151538613af7565b809192505190878215928315613b73575b5050509038613af0565b613b839350820181019101612f03565b388781613b69565b91508782813d8311613bb4575b613ba28183612aee565b810103126103c7575085905138613a67565b503d613b98565b9190811015612dfa5760051b0190565b919091613bd78361319f565b9260005b818110613be757505050565b6001600160a01b03613bfd61250d838587613bbb565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa918215613c8f5750600091613c5e575b5060019250613c57828861328a565b5201613bdb565b919282813d8311613c88575b613c748183612aee565b810103126103c75750906001915138613c48565b503d613c6a565b513d6000823e3d90fd5b6040517f8da5cb5b000000000000000000000000000000000000000000000000000000008152602081600481305afa9081156106cb57600091613cda575090565b6020813d8211613d10575b81613cf260209383612aee565b810103126103ca5751906001600160a01b03821682036103c7575090565b3d9150613ce5565b909160005b818110613d2a5750505050565b6001600160a01b03613d4061250d838588613bbb565b16906040805180937f70a0823100000000000000000000000000000000000000000000000000000000825230600483015281602460209687935afa918215613c8f5750600091613dc4575b5060019250613da8613dbe91613da1848861328a565b5190612e6b565b613db661250d84878a613bbb565b6102c1613c99565b01613d1d565b919282813d8311613df0575b613dda8183612aee565b810103126103c757505160019190613da8613d8b565b503d613dd0565b6001600160a01b031660409081517f70a08231000000000000000000000000000000000000000000000000000000008082526000903060048401526020908184602481885afa938415613f82578394613f53575b50843b156103375785517fd0e30db00000000000000000000000000000000000000000000000000000000081528381600481348a5af18015613f4957613f36575b508190602487518097819382523060048301525afa918215613f2b5791613efb575b50613eb99250612e6b565b90348203613ec5575050565b6044925051907fe5f762580000000000000000000000000000000000000000000000000000000082523460048301526024820152fd5b905082813d8311613f24575b613f118183612aee565b8101031261030657613eb9915138613eae565b503d613f07565b8551903d90823e3d90fd5b92613f42839294612aa2565b9290613e8c565b87513d86823e3d90fd5b9093508181813d8311613f7b575b613f6b8183612aee565b8101031261033757519238613e4b565b503d613f61565b86513d85823e3d90fd5b359065ffffffffffff8216820361030657565b939293613faa613c99565b946001600160a01b0393847f0000000000000000000000000000000000000000000000000000000000000000166000978860c08501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112156103ca5785019485359567ffffffffffffffff871161033757602001863603811361033757843b156103375789604051947f2b67b57000000000000000000000000000000000000000000000000000000000865216968760048601528a61406e84612b27565b16602486015260208301358b811680910361034657601f86949260a086948f601f1995604488015265ffffffffffff806140aa60408501613f8c565b1660648901526140bc60608401613f8c565b1660848801526140ce60808301612b27565b1660a4870152013560c485015261010060e485015280610104850152806101249586860137868582860101520116810103018183865af1801561070f5761419e575b50908188923b156103375786938360849260405196879586947f36c78516000000000000000000000000000000000000000000000000000000008652600486015230602486015216998a6044850152891660648401525af180156141935761417f575b50612f01939450613a07565b6141898691612aa2565b6103465784614173565b6040513d88823e3d90fd5b6141ab9098919298612aa2565b969038614110565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630146141e557565b60046040517fbbff6135000000000000000000000000000000000000000000000000000000008152fd"; + + /*////////////////////////////////////////////////////////////////////////// + DEPLOYERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Deploys {SablierV2Archive} from precompiled bytecode. + function deployArchive(address initialAdmin) public returns (ISablierV2Archive archive) { + bytes memory creationBytecode = bytes.concat(BYTECODE_ARCHIVE, abi.encode(initialAdmin)); + assembly { + archive := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + require(address(archive) != address(0), "Sablier V2 Precompiles: deployment failed for Archive contract"); + } + + /// @notice Deploys {SablierV2ProxyPlugin} from precompiled bytecode. + function deployProxyPlugin(ISablierV2Archive archive) public returns (ISablierV2ProxyPlugin proxyPlugin) { + bytes memory creationBytecode = bytes.concat(BYTECODE_PROXY_PLUGIN, abi.encode(archive)); + assembly { + proxyPlugin := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + require( + address(proxyPlugin) != address(0), "Sablier V2 Precompiles: deployment failed for ProxyPlugin contract" + ); + } + + /// @notice Deploys {SablierV2ProxyTarget} from precompiled bytecode. + function deployProxyTarget(IAllowanceTransfer permit2) public returns (ISablierV2ProxyTarget proxyTarget) { + bytes memory creationBytecode = bytes.concat(BYTECODE_PROXY_TARGET, abi.encode(permit2)); + assembly { + proxyTarget := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + require( + address(proxyTarget) != address(0), "Sablier V2 Precompiles: deployment failed for ProxyTarget contract" + ); + } + + /// @notice Deploys all V2 Periphery contracts in the following order: + /// + /// 1. {SablierV2Archive} + /// 2. {SablierV2ProxyPlugin} + /// 3. {SablierV2ProxyTarget} + function deployPeriphery( + address initialAdmin, + IAllowanceTransfer permit2 + ) + public + returns (ISablierV2Archive archive, ISablierV2ProxyPlugin proxyPlugin, ISablierV2ProxyTarget proxyTarget) + { + archive = deployArchive(initialAdmin); + proxyPlugin = deployProxyPlugin(archive); + proxyTarget = deployProxyTarget(permit2); + } +} diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol new file mode 100644 index 00000000..b912dc4b --- /dev/null +++ b/test/utils/Precompiles.t.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.19 <=0.9.0; + +import { IAllowanceTransfer } from "permit2/interfaces/IAllowanceTransfer.sol"; +import { DeployPermit2 } from "permit2-test/utils/DeployPermit2.sol"; +import { LibString } from "solady/utils/LibString.sol"; + +import { ISablierV2Archive } from "../../src/interfaces/ISablierV2Archive.sol"; +import { ISablierV2ProxyPlugin } from "../../src/interfaces/ISablierV2ProxyPlugin.sol"; +import { ISablierV2ProxyTarget } from "../../src/interfaces/ISablierV2ProxyTarget.sol"; + +import { Base_Test } from "../Base.t.sol"; +import { Precompiles } from "./Precompiles.sol"; + +contract Precompiles_Test is Base_Test { + using LibString for address; + using LibString for string; + + Precompiles internal precompiles = new Precompiles(); + + modifier onlyTestOptimizedProfile() { + if (isTestOptimizedProfile()) { + _; + } + } + + function test_DeployArchive() external onlyTestOptimizedProfile { + address actualArchive = address(precompiles.deployArchive(users.admin.addr)); + address expectedArchive = address(deployPrecompiledArchive(users.admin.addr)); + assertEq(actualArchive.code, expectedArchive.code, "bytecodes mismatch"); + } + + function test_DeployProxyPlugin() external onlyTestOptimizedProfile { + ISablierV2Archive archive = deployPrecompiledArchive(users.admin.addr); + address actualProxyPlugin = address(precompiles.deployProxyPlugin(archive)); + address expectedProxyPlugin = address(deployPrecompiledProxyPlugin(archive)); + bytes memory expectedProxyPluginCode = + adjustBytecode(expectedProxyPlugin.code, expectedProxyPlugin, actualProxyPlugin); + assertEq(actualProxyPlugin.code, expectedProxyPluginCode, "bytecodes mismatch"); + } + + function test_DeployProxyTarget() external onlyTestOptimizedProfile { + IAllowanceTransfer permit2 = IAllowanceTransfer(new DeployPermit2().run()); + address actualProxyTarget = address(precompiles.deployProxyTarget(permit2)); + address expectedProxyTarget = address(deployPrecompiledProxyTarget(permit2)); + bytes memory expectedProxyTargetCode = + adjustBytecode(expectedProxyTarget.code, expectedProxyTarget, actualProxyTarget); + assertEq(actualProxyTarget.code, expectedProxyTargetCode, "bytecodes mismatch"); + } + + function test_DeployPeriphery() external onlyTestOptimizedProfile { + IAllowanceTransfer permit2 = IAllowanceTransfer(new DeployPermit2().run()); + ( + ISablierV2Archive actualArchive, + ISablierV2ProxyPlugin actualProxyPlugin, + ISablierV2ProxyTarget actualProxyTarget + ) = precompiles.deployPeriphery(users.admin.addr, permit2); + + address expectedArchive = address(deployPrecompiledArchive(users.admin.addr)); + assertEq(address(actualArchive).code, expectedArchive.code, "bytecodes mismatch"); + + address expectedProxyPlugin = address(deployPrecompiledProxyPlugin(actualArchive)); + bytes memory expectedLockupDynamicCode = + adjustBytecode(expectedProxyPlugin.code, expectedProxyPlugin, address(actualProxyPlugin)); + assertEq(address(actualProxyPlugin).code, expectedLockupDynamicCode, "bytecodes mismatch"); + + address expectedProxyTarget = address(deployPrecompiledProxyTarget(permit2)); + bytes memory expectedProxyTargetCode = + adjustBytecode(expectedProxyTarget.code, expectedProxyTarget, address(actualProxyTarget)); + assertEq(address(actualProxyTarget).code, expectedProxyTargetCode, "bytecodes mismatch"); + } + + /// @dev The expected bytecode has to be adjusted because some contracts inherit from {NoDelegateCall}, which + /// saves the contract's own address in storage. + function adjustBytecode( + bytes memory bytecode, + address expectedAddress, + address actualAddress + ) + internal + pure + returns (bytes memory) + { + return vm.parseBytes( + vm.toString(bytecode).replace({ + search: expectedAddress.toHexStringNoPrefix(), + replacement: actualAddress.toHexStringNoPrefix() + }) + ); + } +}