From 7f2dd5014c511c0484b2943b01be7256d17cbdc6 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 28 Oct 2024 11:40:17 +0000 Subject: [PATCH] feat: refundMax --- benchmark/Flow.Gas.t.sol | 10 ++- benchmark/results/SablierFlow.md | 25 +++--- precompiles/Precompiles.sol | 2 +- src/SablierFlow.sol | 15 ++++ src/interfaces/ISablierFlow.sol | 10 +++ .../concrete/refund-max/refundMax.t.sol | 77 +++++++++++++++++++ .../concrete/refund-max/refundMax.tree | 21 +++++ tests/integration/fuzz/refundMax.t.sol | 76 ++++++++++++++++++ 8 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 tests/integration/concrete/refund-max/refundMax.t.sol create mode 100644 tests/integration/concrete/refund-max/refundMax.tree create mode 100644 tests/integration/fuzz/refundMax.t.sol diff --git a/benchmark/Flow.Gas.t.sol b/benchmark/Flow.Gas.t.sol index 29d34c37..39dfe554 100644 --- a/benchmark/Flow.Gas.t.sol +++ b/benchmark/Flow.Gas.t.sol @@ -72,8 +72,14 @@ contract Flow_Gas_Test is Integration_Test { // {flow.pause} computeGas("pause", abi.encodeCall(flow.pause, (streamId))); - // {flow.refund} - computeGas("refund", abi.encodeCall(flow.refund, (streamId, REFUND_AMOUNT_6D))); + // {flow.refund} on an incremented stream ID + computeGas("refund", abi.encodeCall(flow.refund, (++streamId, REFUND_AMOUNT_6D))); + + // {flow.refundMax} on an incremented stream ID. + computeGas("refundMax", abi.encodeCall(flow.refundMax, (++streamId))); + + // Pause the current stream to test the restart function. + flow.pause(streamId); // {flow.restart} computeGas("restart", abi.encodeCall(flow.restart, (streamId, RATE_PER_SECOND))); diff --git a/benchmark/results/SablierFlow.md b/benchmark/results/SablierFlow.md index 4cf1f217..22ced93b 100644 --- a/benchmark/results/SablierFlow.md +++ b/benchmark/results/SablierFlow.md @@ -2,15 +2,16 @@ | Function | Gas Usage | | ----------------------------- | --------- | -| `adjustRatePerSecond` | 44171 | -| `create` | 113681 | -| `deposit` | 32975 | -| `depositViaBroker` | 22732 | -| `pause` | 7522 | -| `refund` | 11939 | -| `restart` | 7036 | -| `void (solvent stream)` | 10060 | -| `void (insolvent stream)` | 37460 | -| `withdraw (insolvent stream)` | 57688 | -| `withdraw (solvent stream)` | 38156 | -| `withdrawMax` | 51988 | +| `adjustRatePerSecond` | 44193 | +| `create` | 113703 | +| `deposit` | 32997 | +| `depositViaBroker` | 22754 | +| `pause` | 7544 | +| `refund` | 22842 | +| `refundMax` | 23840 | +| `restart` | 7058 | +| `void (solvent stream)` | 9982 | +| `void (insolvent stream)` | 37482 | +| `withdraw (insolvent stream)` | 57711 | +| `withdraw (solvent stream)` | 38178 | +| `withdrawMax` | 52010 | diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 389df674..43c8f140 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -13,7 +13,7 @@ import { ISablierFlow } from "./../src/interfaces/ISablierFlow.sol"; /// but allows for execution in test environments, such as a local development network or a testnet. contract Precompiles { bytes public constant BYTECODE_FLOW = - hex"60a0604052346103a9576148626040813803918261001c816103ad565b9384928339810103126103a95780516001600160a01b03811691908290036103a957602001516001600160a01b038116908190036103a95761005e60406103ad565b91601083526f14d8589b1a595c88119b1bddc813919560821b602084015261008660406103ad565b60088152675341422d464c4f5760c01b60208201523060805283519092906001600160401b0381116102ba57600154600181811c9116801561039f575b602082101461029c57601f811161033c575b50602094601f82116001146102d9579481929394955f926102ce575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102ba57600254600181811c911680156102b0575b602082101461029c57601f8111610239575b506020601f82116001146101d657819293945f926101cb575b50508160011b915f199060031b1c1916176002555b60016008555f80546001600160a01b031990811684178255600980549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a361448f90816103d3823960805181612ffe0152f35b015190505f80610152565b601f1982169060025f52805f20915f5b81811061022157509583600195969710610209575b505050811b01600255610167565b01515f1960f88460031b161c191690555f80806101fb565b9192602060018192868b0151815501940192016101e6565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c81019160208410610292575b601f0160051c01905b8181106102875750610139565b5f815560010161027a565b9091508190610271565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610127565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100f1565b601f1982169560015f52805f20915f5b8881106103245750836001959697981061030c575b505050811b01600155610106565b01515f1960f88460031b161c191690555f80806102fe565b919260206001819286850151815501940192016102e9565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610395575b601f0160051c01905b81811061038a57506100d5565b5f815560010161037d565b9091508190610374565b90607f16906100c3565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102ba5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146125e35750806306fdde0314612528578063081812fc1461250a57806308b87923146124d0578063095ea7b3146123b35780630c5fd19514612372578063136439dd146122da5780631400ecec146122a05780631e010439146122525780631e897afb146121295780631e99d5691461210c5780631f0cce5814611ff757806323b872dd14611fe0578063379d871a14611f3f57806342842e0e14611f1657806342e3e23d146108bb5780634426757014611ef0578063569f4c5914611ea0578063597150fa14611e585780635ea2145b14611b2c5780635f55315214611af45780636352211e14611ac5578063648bf7741461196c5780636d0cee751461191e57806370a08231146118b457806375829def1461182e5780637cad6cd11461170357806380448da3146116bb57806381632a861461162f578063894e9a0d1461148257806395d89b41146113435780639e9e2e13146112bc578063a22cb465146111ea578063a7de07cd1461119c578063a8a482a614611092578063ad35efd41461101a578063b256456914610fe5578063b5b3ca2c14610f15578063b62b31e414610edd578063b88d4fde14610e53578063b8a3be6614610e1e578063b971302a14610dcd578063bc063e1a14610dab578063bc7a2d6c14610d71578063bcbd019e14610c9b578063bdf2a43c14610c52578063c87b56dd14610b3c578063c928801914610962578063d4b80884146108d9578063d975dfed146108bb578063dcd7a5331461086a578063e4b50cb814610819578063e985e9c5146107c0578063ea5ead1914610730578063eb5710d8146106de578063ebb6f79a146105b0578063edfa12df1461053a578063f851a44014610515578063fbf2777e1461049e578063fdd46d60146103f25763ffe3d9f8146102bb575f80fd5b346103ee5760406003193601126103ee576102d4612716565b6102dc61272c565b6001600160a01b035f54163381036103bf57506001600160a01b03821691825f52600b6020526001600160801b0360405f20541690811561039357818361035792865f52600b60205260405f206fffffffffffffffffffffffffffffffff198154169055865f52600760205260405f20838154039055613ae5565b6001600160a01b036040519216825260208201527fc9a4a66b97fd7e52e69c5be7b10bdc5341bded817201b9b7136a75068d4e4e0560403392a3005b837ff717901b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b5f80fd5b346103ee5760606003193601126103ee5760043561040e61272c565b61041661276e565b9061041f612ff4565b825f52600c60205260ff600160405f20015460c81c161561047257916104696020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79483613da1565b604051908152a1005b827fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760c06003193601126103ee576104b7612716565b6104bf61272c565b906104c861276e565b916104d1612742565b916104da6127be565b60a435936001600160801b03851685036103ee5760209561050d9461050694610501612ff4565b613526565b9182613273565b604051908152f35b346103ee575f6003193601126103ee5760206001600160a01b035f5416604051908152f35b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c161561058557610574602091613cb5565b6001600160801b0360405191168152f35b7fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760406003193601126103ee576004356105cc612758565b6105d4612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c60205260ff600160405f20015460d81c1661068657815f52600c6020526001600160a01b03600160405f20015416330361065657816104696020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7946131f3565b507fa9ad2a22000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b507f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b507fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c602052602064ffffffffff600160405f20015460a01c16604051908152f35b346103ee5760406003193601126103ee5760043561074c61272c565b610754612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b2577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020836107a86107a083966134e6565b809583613da1565b604051908152a16001600160801b0360405191168152f35b346103ee5760406003193601126103ee576107d9612716565b6001600160a01b036107e961272c565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c60205260206001600160a01b03600260405f20015416604051908152f35b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c60205260206001600160801b03600360405f20015416604051908152f35b346103ee5760206003193601126103ee576020610574600435612b99565b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c161561058557805f52600c60205260405f205460801c1561093757610928602091612e37565b64ffffffffff60405191168152f35b7f167274c9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760806003193601126103ee5760043561097e612758565b60407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc3601126103ee576109b0612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c60205260ff600160405f20015460d81c1661068657604051916040830183811067ffffffffffffffff821117610b0f576040526044356001600160a01b03811681036103ee578352606435602084019080825267016345785d8a00008111610ad857506001600160a01b0384511615610ab0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793610a82610a796020956104699451906142c7565b85929192613273565b835f52600c85526001600160801b036001600160a01b0380600260405f20015416935116911691339061416d565b7f5f946a02000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f54b392b2000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b346103ee5760206003193601126103ee57600435610b5981612f7c565b505f6001600160a01b0360095416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610c47575f90610bca575b610bc6906040519182916020835260208301906126d3565b0390f35b503d805f833e610bda81836127ea565b8101906020818303126103ee5780519067ffffffffffffffff82116103ee57019080601f830112156103ee57815191610c128361282b565b91610c2060405193846127ea565b838352602084830101116103ee57610bc692610c4291602080850191016126b2565b610bae565b6040513d5f823e3d90fd5b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c602052602060405f205460801c15604051908152f35b346103ee5760406003193601126103ee57600435610cb7612758565b610cbf612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c60205260405f205460801c15610d4557815f52600c6020526001600160a01b03600160405f2001541633036106565781610d3c6020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794613273565b6104698161304e565b507f167274c9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c161561058557610574602091613c7b565b346103ee575f6003193601126103ee57602060405167016345785d8a00008152f35b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c60205260206001600160a01b03600160405f20015416604051908152f35b346103ee5760206003193601126103ee576004355f52600c602052602060ff600160405f20015460c81c166040519015158152f35b346103ee5760806003193601126103ee57610e6c612716565b610e7461272c565b6064359167ffffffffffffffff83116103ee57366023840112156103ee57826004013591610ea18361282b565b92610eaf60405194856127ea565b80845236602482870101116103ee576020815f926024610edb9801838801378501015260443591612c24565b005b346103ee5760206003193601126103ee576001600160a01b03610efe612716565b165f52600a602052602060405f2054604051908152f35b346103ee5760406003193601126103ee57610f2e612716565b602435906001600160a01b035f54163381036103bf575067016345785d8a00008211610fad576001600160a01b031690815f52600a60205260405f205490825f52600a6020528060405f205560405191825260208201527f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d60403392a3005b507f34553172000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b346103ee5760206003193601126103ee576004355f52600c602052602060ff600160405f20015460d01c166040519015158152f35b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c16156105855761105290612bc0565b6040516005821015611065576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b346103ee5760406003193601126103ee576004356110ae612758565b6110b6612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c60205260405f205460801c15610d4557815f52600c6020526001600160a01b03600160405f2001541633036106565781807f3c92c3a56d04d4a7bc02d85874ad093d97053f2b046ef83860ecd0df273079b960606020947ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7965f52600c86526001600160801b0360405f205460801c916111708187613b41565b855f52600c885281600360405f200154169260405193845288840152166040820152a2604051908152a1005b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c602052602060ff600260405f20015460a01c16604051908152f35b346103ee5760406003193601126103ee57611203612716565b602435908115158092036103ee576001600160a01b031690811561129057335f52600660205260405f20825f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760406003193601126103ee576004356112d8612758565b6112e0612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c60205260ff600160405f20015460d81c1661068657816104696020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794613273565b346103ee575f6003193601126103ee576040515f6002548060011c90600181168015611478575b60208310811461144b5782855290811561140957506001146113ab575b610bc683611397818503826127ea565b6040519182916020835260208301906126d3565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113ef57509091508101602001611397611387565b9192600181602092548385880101520191019092916113d7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506113979050611387565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f169161136a565b346103ee5760206003193601126103ee576004355f6101206040516114a6816127cd565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201520152805f52600c60205260ff600160405f20015460c81c1615610585575f52600c60205260405f2060405161150e816127cd565b81546001600160801b03811692838352602083019160801c82526001810154604084016001600160a01b0382168152606085018260a01c64ffffffffff16815260808601908360c81c60ff161515825260a08701928460d01c60ff161515845260c088019460d81c60ff161515855260028601549660e08901966001600160a01b03891688526101008a019860a01c60ff168952600301546001600160801b03169861012001988952604051998a52516001600160801b031660208a0152516001600160a01b031660408901525164ffffffffff166060880152511515608087015251151560a086015251151560c0850152516001600160a01b031660e08401525160ff16610100830152516001600160801b031661012082015261014090f35b346103ee5760406003193601126103ee5760043561164b612758565b611653612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c6020526001600160a01b03600160405f20015416330361065657816104696020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79461334d565b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c602052602060405f205460801c604051908152f35b346103ee5760206003193601126103ee576004356001600160a01b0381168091036103ee576001600160a01b035f54163381036103bf575060095490807fffffffffffffffffffffffff00000000000000000000000000000000000000008316176009556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26008547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116118015760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b346103ee5760206003193601126103ee57611847612716565b5f546001600160a01b0381163381036103bf57506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346103ee5760206003193601126103ee576001600160a01b036118d5612716565b1680156118f2575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600360205260206001600160a01b0360405f205416604051908152f35b346103ee5760406003193601126103ee57611985612716565b61198d61272c565b6001600160a01b035f54163381036103bf57506040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03831692602082602481875afa918215610c47575f92611a91575b50835f52600760205260405f2054808303928084116118015714611a655781611a3c7f21252411d5a999da4bc6a490f7143b61ba690edceb4577a2800eab8dfbb1e92c9385611a6094613ae5565b604051918291339583602090939291936001600160a01b0360408201951681520152565b0390a3005b837ff4c3afcf000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011611abd575b81611aad602093836127ea565b810103126103ee575190846119ee565b3d9150611aa0565b346103ee5760206003193601126103ee576020611ae3600435612f7c565b6001600160a01b0360405191168152f35b346103ee5760206003193601126103ee576001600160a01b03611b15612716565b165f526007602052602060405f2054604051908152f35b346103ee5760206003193601126103ee57600435611b48612ff4565b805f52600c60205260ff600160405f20015460c81c161561058557805f52600c60205260ff600160405f20015460d81c16611e2d57805f52600c6020526001600160a01b03600160405f2001541633141580611e1d575b611dee57602081611bd07ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793613c7b565b6001600160801b038116611da457611be782613cb5565b6001600160801b038116611d62575b505b5f828152600c84526040902060010180547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff164260a01b78ffffffffff000000000000000000000000000000000000000016179055815f52600c835260405f206001600160801b038154169055815f52600c8352600160405f20017b010000000000000000000000000000000000000000000000000000007fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff825416179055815f52600c83526001600160a01b03600160405f20015416825f5260038452827f35f9aa46e14f354fc906578188ddcf18c75e64b520fa7ee83ee1926069c59ef46001600160a01b0360405f20541693825f52600c87526001600160801b03600360405f20015416611d5660405192839233849160409194936001600160801b0380926001600160a01b03606087019816865216602085015216910152565b0390a4604051908152a1005b825f52600c84526001600160801b03611d85600360405f20019282845416612dcc565b166fffffffffffffffffffffffffffffffff1982541617905584611bf6565b815f52600c83526001600160801b0360405f205416825f52600c84526001600160801b03600360405f200191166fffffffffffffffffffffffffffffffff19825416179055611bf8565b7fa9ad2a22000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b50611e27816141c7565b15611b9f565b7f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee5760a06003193601126103ee57602061050d611e76612716565b611e7e61272c565b611e8661276e565b611e8e612742565b91611e976127be565b93610501612ff4565b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c602052602060ff600160405f20015460d81c166040519015158152f35b346103ee575f6003193601126103ee5760206001600160a01b0360095416604051908152f35b346103ee57610edb611f2736612784565b9060405192611f376020856127ea565b5f8452612c24565b346103ee5760406003193601126103ee57600435611f5b612758565b611f63612ff4565b815f52600c60205260ff600160405f20015460c81c16156106b257815f52600c60205260405f205460801c15610d4557815f52600c6020526001600160a01b03600160405f2001541633036106565781610d3c6020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79461334d565b346103ee57610edb611ff136612784565b916128b6565b346103ee5760606003193601126103ee57600435612013612758565b61201b61276e565b90612024612ff4565b825f52600c60205260ff600160405f20015460c81c161561047257825f52600c60205260ff600160405f20015460d81c166120e057825f52600c6020526001600160a01b03600160405f2001541633036120b057916104696020926120aa7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce795846131f3565b82613273565b827fa9ad2a22000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b827f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346103ee575f6003193601126103ee576020600854604051908152f35b346103ee5760206003193601126103ee5760043567ffffffffffffffff81116103ee57366023820112156103ee57806004013567ffffffffffffffff81116103ee573660248260051b840101116103ee57905f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd81360301915b83811015610edb5760248160051b83010135838112156103ee57820160248101359067ffffffffffffffff82116103ee5760440181360381136103ee57815f92918392604051928392833781018381520390305af4612201612887565b901561221057506001016121a4565b61224e906040519182917fd93544850000000000000000000000000000000000000000000000000000000083526020600484015260248301906126d3565b0390fd5b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585575f52600c60205260206001600160801b0360405f205416604051908152f35b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c1615610585576105746020916131ca565b346103ee5760206003193601126103ee576004356122f6612ff4565b805f52600c60205260ff600160405f20015460c81c161561058557805f52600c60205260405f205460801c1561093757805f52600c6020526001600160a01b03600160405f200154163303611dee576020816104697ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79361304e565b346103ee5760206003193601126103ee576001600160a01b03612393612716565b165f52600b60205260206001600160801b0360405f205416604051908152f35b346103ee5760406003193601126103ee576123cc612716565b6024356123d881612f7c565b331515806124bd575b8061248a575b61245e5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156123e7565b50336001600160a01b03821614156123e1565b346103ee5760206003193601126103ee57600435805f52600c60205260ff600160405f20015460c81c161561058557610574602091612fc8565b346103ee5760206003193601126103ee576020611ae3600435612865565b346103ee575f6003193601126103ee576040515f6001548060011c906001811680156125d9575b60208310811461144b57828552908115611409575060011461257b57610bc683611397818503826127ea565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106125bf57509091508101602001611397611387565b9192600181602092548385880101520191019092916125a7565b91607f169161254f565b346103ee5760206003193601126103ee57600435907fffffffff0000000000000000000000000000000000000000000000000000000082168092036103ee57817f80ac58cd0000000000000000000000000000000000000000000000000000000060209314908115612688575b811561265e575b5015158152f35b7f01ffc9a70000000000000000000000000000000000000000000000000000000091501483612657565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612650565b5f5b8381106126c35750505f910152565b81810151838201526020016126b4565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361270f815180928187528780880191016126b2565b0116010190565b600435906001600160a01b03821682036103ee57565b602435906001600160a01b03821682036103ee57565b606435906001600160a01b03821682036103ee57565b602435906001600160801b03821682036103ee57565b604435906001600160801b03821682036103ee57565b60031960609101126103ee576004356001600160a01b03811681036103ee57906024356001600160a01b03811681036103ee579060443590565b6084359081151582036103ee57565b610140810190811067ffffffffffffffff821117610b0f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b0f57604052565b67ffffffffffffffff8111610b0f57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b61286e81612f7c565b505f5260056020526001600160a01b0360405f20541690565b3d156128b1573d906128988261282b565b916128a660405193846127ea565b82523d5f602084013e565b606090565b91906001600160a01b0316918215612b6d57815f5260036020526001600160a01b0360405f205416151580612b50575b612b2457815f5260036020526001600160a01b0360405f2054169233151580612a5c575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce760206001600160a01b0393866129ef575b805f526004825260405f2060018154019055855f526003825260405f20817fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558560405191887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4858152a1168083036129be57505050565b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b612a26865f52600560205260405f207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b865f526004825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815401905561293e565b80612acd575b15612a6d575f61290a565b8284612a9e577f7e273289000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612afb575b80612a625750825f526005602052336001600160a01b0360405f20541614612a62565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612ad8565b507f7da2ea2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50815f52600c60205260ff600160405f20015460d01c16156128e6565b7f64a0ae92000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b805f52600c60205260ff600160405f20015460c81c161561058557612bbd906134e6565b90565b805f52600c60205260ff600160405f20015460d81c16612c1e576001600160801b03612beb82613c7b565b161515905f52600c60205260405f205460801c15612c1057612c0b575f90565b600190565b612c1957600290565b600390565b50600490565b90612c308382846128b6565b803b612c3d575b50505050565b602091612c9c6001600160a01b038093169560405195869485947f150b7a0200000000000000000000000000000000000000000000000000000000865233600487015216602485015260448401526080606484015260848301906126d3565b03815f865af15f9181612d6f575b50612cf15750612cb8612887565b80519081612cec57827f64a0ae92000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000007f150b7a0200000000000000000000000000000000000000000000000000000000911603612d4457505f808080612c37565b7f64a0ae92000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011612dc4575b81612d8b602093836127ea565b810103126103ee57517fffffffff00000000000000000000000000000000000000000000000000000000811681036103ee57905f612caa565b3d9150612d7e565b906001600160801b03809116911601906001600160801b03821161180157565b906001600160801b0316908115612e0a576001600160801b03160490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b805f52600c6020526001600160801b0360405f2054168015612f7657815f52600c6020526001600160801b03600360405f20015416816001600160801b03612e87612e8186613cb5565b84612dcc565b161015612f6f57612edb916001600160801b0391845f52600c60205260ff600260405f20015460a01c16601281145f14612f4c575090038116600101165b825f52600c60205260405f205460801c90612dec565b6001600160801b038116915f52600c60205264ffffffffff600160405f20015460a01c169164ffffffffff8111612f1c57509064ffffffffff809216011690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52602860045260245260445ffd5b838092612f6360ff60019460120316600a0a613d57565b94031601160216612ec5565b5050505f90565b50505f90565b805f5260036020526001600160a01b0360405f205416908115612f9d575090565b7f7e273289000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612bbd90805f52600c602052612fee6001600160801b03600360405f2001541691613cb5565b90612dcc565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361302657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f52600c60205260405f205460801c1561317b5761306c81613cb5565b6001600160801b038116613138575b505f818152600c6020818152604080842060018101805478ffffffffff00000000000000000000000000000000000000004260a01b167fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff82161790915581546001600160801b03908116835560038086529684902054958552959091015491519190941681526001600160a01b039283169492909316927f3d86c5ea0db69a6591bd7fc8ffb71b4d5ae3666e3020b5382c920d631ebad19c9190a4565b815f52600c6020526001600160801b0361315c600360405f20019282845416612dcc565b166fffffffffffffffffffffffffffffffff198254161790555f61307b565b7fd2657d5a000000000000000000000000000000000000000000000000000000005f526004525f60245260445ffd5b906001600160801b03809116911603906001600160801b03821161180157565b612bbd90805f52600c6020526131ed6001600160801b0360405f205416916134e6565b906131aa565b805f52600c60205260405f205460801c613248576132118282613b41565b6001600160801b03604051921682527fc2a543cfadbf862642247e28711aaa30e3460384be5712be6557fee3384454fd60203393a3565b7fdc6fbbbc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6001600160801b038216918215613321575f828152600c60205260409020600281015481546132f39386936001600160a01b0390931692916001600160801b03916132bf918316612dcc565b166fffffffffffffffffffffffffffffffff19825416179055805f52600760205260405f208281540190553090339061416d565b6040519182527fa06c1466b3c9751408a5ac337a2e8808e5ee0ceed1fd70635d041b21174eb6b460203393a3565b507f33f2df5a000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6001600160801b03821680156134ba576001600160801b0361336e836131ca565b1680821161348857825f52600c6020526001600160801b0360405f2054161061343f5760207fe31f2d40d5780915b1e656a67e11bdf09b0a4a925ec42bbeae220c8ca937ab4991835f52600c8252613436816001600160a01b03600160405f200154168097875f52600c86526001600160a01b03600260405f2001541690885f52600c87526001600160801b038060405f2092818454160316166fffffffffffffffffffffffffffffffff19825416179055805f526007865260405f20838154039055613ae5565b604051908152a3565b90805f52600c6020526001600160801b0360405f205416907fcb5f605f000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b917fe9771401000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b507fea66b871000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b805f52600c6020526001600160801b0360405f205416908115612f765761350c90612fc8565b906001600160801b0382168110613521575090565b905090565b6001600160a01b039095949293919516908115613abd576001600160a01b0316926040517f313ce567000000000000000000000000000000000000000000000000000000008152602081600481885afa8015610c47575f90613a80575b60ff9150169560128711613a5457600854968786604051926135a4846127cd565b5f845260208401956001600160801b031695868152604085019088825260608601994264ffffffffff168b52608087016001815260a088019115159b8c835260c08901935f855260e08a019788526101008a019687526101208a01985f8a525f52600c60205260405f2099516001600160801b03166001600160801b03168a546fffffffffffffffffffffffffffffffff1916178a55516001600160801b0316613672908a906001600160801b036fffffffffffffffffffffffffffffffff1983549260801b169116179055565b9351600189018054955178ffffffffff000000000000000000000000000000000000000060a09190911b166001600160a01b039092167fffffffffffffff00000000000000000000000000000000000000000000000000909616959095171784555115159083549051151560d01b7aff0000000000000000000000000000000000000000000000000000169160c81b79ff0000000000000000000000000000000000000000000000000016907fffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff161717825551151581549060d81b7bff00000000000000000000000000000000000000000000000000000016907fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff161790556002840191516001600160a01b03166001600160a01b031682547fffffffffffffffffffffffff0000000000000000000000000000000000000000161782555181549060a01b74ff000000000000000000000000000000000000000016907fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16179055516001600160801b031690600301906001600160801b031681546fffffffffffffffffffffffffffffffff1916179055600187016008556001600160a01b0316928315612b6d57865f5260036020526001600160a01b0360405f205416151580613a37575b613a0b57865f5260036020526001600160a01b0360405f2054167ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020821515928361399e575b875f526004825260405f20600181540190558a5f526003825260405f20887fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055604051908b89827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4508a8152a1613972577f2262fa211f8507786a60fefb231f7898b8145fe16350f281c91f121bd2ee118d916060916040519189835260208301526040820152a4565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b6139d58b5f52600560205260405f207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b805f526004825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81540190556138c0565b867f7da2ea2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50865f52600c60205260ff600160405f20015460d01c1615613879565b847fc9f55392000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506020813d602011613ab5575b81613a9a602093836127ea565b810103126103ee575160ff811681036103ee5760ff90613583565b3d9150613a8d565b7ff9bb0fb3000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152613b3f91613b3a6064836127ea565b614239565b565b91906001600160801b03811692805f52600c60205260405f205460801c8414613c4b57613b3f929350613b7381613cb5565b6001600160801b038116613c08575b505f908152600c6020526040902060018101805478ffffffffff00000000000000000000000000000000000000004260a01b167fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff90911617905580546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff1916919091179055565b815f52600c6020526001600160801b03613c2c600360405f20019282845416612dcc565b166fffffffffffffffffffffffffffffffff198254161790555f613b82565b83907fd2657d5a000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b805f52600c602052613c9a6001600160801b0360405f20541691612fc8565b906001600160801b038216811015612f7657612bbd916131aa565b5f818152600c602052604090206001810154905464ffffffffff4281169360809290921c9260a01c1682158015613d4d575b613d455764ffffffffff915f52600c60205260ff600260405f20015460a01c1693031602906001600160801b0382169182036118015760128114613d415790613d3b60ff612bbd9360120316600a0a613d57565b90612dec565b5090565b505050505f90565b5080841115613ce7565b6001600160801b038111613d71576001600160801b031690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52608060045260245260445ffd5b6001600160801b038316928315614141576001600160a01b03831692831561411557825f5260036020526001600160a01b0360405f20541684141580614105575b6140d157613def83612fc8565b94835f52600c6020526001600160801b0360405f205416906001600160801b03871682105f146140c3576001600160801b03825b1680821161409057505f858152600c60205260409020600301546001600160801b03161061400d57835f52600c602052600360405f20016001600160801b038085818454160316166fffffffffffffffffffffffffffffffff198254161790555b5f848152600c6020908152604080832080546001600160801b03808216899003166fffffffffffffffffffffffffffffffff19909116178155600201546001600160a01b0316808452600a909252822054909791939080613faf575b50613f30613f1a6001600160801b0393613f118594858a16908d5f52600760205260405f208281540390558d613ae5565b6131ed89612fc8565b93875f52600c6020528260405f205416906131aa565b16911603613f8257604080513381526001600160801b03938416602082015291909216918101919091527f1a7b0d6c8f96b874563b711cf97793fe3be5dc42dbd1e0720ce40f326918e81790606090a4565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b613f119450613f1a6001600160801b0393613fcf613f30938695996142c7565b97909798888d5f52600b602052868060405f2092818454160116166fffffffffffffffffffffffffffffffff19825416179055945050935050613ee0565b5f848152600c602052604090206003810180546fffffffffffffffffffffffffffffffff19168589036001600160801b031617905560010180547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff164260a01b78ffffffffff000000000000000000000000000000000000000016179055613e84565b90857ff9f29859000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b6001600160801b0387613e23565b50507f4208ab4c000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061410f836141c7565b15613de2565b827f9f32c858000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b507fb4855052000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091926001600160a01b03613b3f9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252613b3a6084836127ea565b805f5260036020526001600160a01b0360405f2054169081331491821561420d575b5081156141f4575090565b90506001600160a01b036142083392612865565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6141e9565b5f806001600160a01b0361426293169360208151910182865af161425b612887565b90836143f6565b80519081151591826142a3575b50506142785750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126103ee57602001518015908115036103ee575f8061426f565b91906142dc906001600160801b038416614329565b6001600160801b0381116142fe576001600160801b03612bbd911680936131aa565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838209838202918280831092039180830392146143e557670de0b6b3a76400008210156143b5577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614433575080511561440b57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614479575b614444575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561443c56fea164736f6c634300081a000a"; + hex"60a0604052346103a957614b956040813803918261001c816103ad565b9384928339810103126103a95780516001600160a01b03811691908290036103a957602001516001600160a01b038116908190036103a95761005e60406103ad565b91601083526f14d8589b1a595c88119b1bddc813919560821b602084015261008660406103ad565b60088152675341422d464c4f5760c01b60208201523060805283519092906001600160401b0381116102ba57600154600181811c9116801561039f575b602082101461029c57601f811161033c575b50602094601f82116001146102d9579481929394955f926102ce575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102ba57600254600181811c911680156102b0575b602082101461029c57601f8111610239575b506020601f82116001146101d657819293945f926101cb575b50508160011b915f199060031b1c1916176002555b60016008555f80546001600160a01b031990811684178255600980549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36147c290816103d38239608051816131510152f35b015190505f80610152565b601f1982169060025f52805f20915f5b81811061022157509583600195969710610209575b505050811b01600255610167565b01515f1960f88460031b161c191690555f80806101fb565b9192602060018192868b0151815501940192016101e6565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c81019160208410610292575b601f0160051c01905b8181106102875750610139565b5f815560010161027a565b9091508190610271565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610127565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100f1565b601f1982169560015f52805f20915f5b8881106103245750836001959697981061030c575b505050811b01600155610106565b01515f1960f88460031b161c191690555f80806102fe565b919260206001819286850151815501940192016102e9565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610395575b601f0160051c01905b81811061038a57506100d5565b5f815560010161037d565b9091508190610374565b90607f16906100c3565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102ba5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127675750806306fdde03146126ac578063081812fc1461268e57806308b8792314612654578063095ea7b3146125375780630c5fd195146124ed5780630c69962414612461578063136439dd146123c95780631400ecec1461238f5780631e010439146123385780631e897afb1461220f5780631e99d569146121f25780631f0cce58146120e357806323b872dd146120cc578063379d871a1461202b57806342842e0e1461200257806342e3e23d146108665780634426757014611fdc578063450ac90814611f94578063569f4c5914611f44578063597150fa14611efc5780635ea2145b14611c295780635f55315214611bf15780636352211e14611bc2578063648bf77414611a695780636d0cee7514611a1b57806370a08231146119b157806375829def1461192b5780637cad6cd11461182d5780637ddf9228146117f357806380448da3146117ab57806381632a861461171f578063894e9a0d1461157257806395d89b4114611433578063a22cb46514611361578063a7de07cd14611313578063a8a482a614611208578063ad35efd414611190578063b256456914611140578063b5b3ca2c14610fe5578063b61f758314610f42578063b62b31e414610f0a578063b88d4fde14610e80578063b8a3be6614610e4b578063b971302a14610dfa578063bc063e1a14610dd8578063bc7a2d6c14610d9e578063bcbd019e14610cc8578063bdf2a43c14610c7f578063c2f8e75014610a2a578063c87b56dd14610918578063d4b808841461089e578063d975dfed14610866578063e4b50cb814610815578063e985e9c5146107bc578063ea5ead1914610745578063eb5710d8146106c8578063ebb6f79a14610591578063f851a4401461056c578063fbf2777e146104ec578063fdd46d60146104155763ffe3d9f8146102c6575f80fd5b34610411576040600319360112610411576102df61289a565b6102e76128b0565b6001600160a01b035f54163381036103e257506001600160a01b03821691825f52600b6020526fffffffffffffffffffffffffffffffff60405f2054169081156103b657818361037a92865f52600b60205260405f207fffffffffffffffffffffffffffffffff000000000000000000000000000000008154169055865f52600760205260405f20838154039055613cc3565b6001600160a01b036040519216825260208201527fc9a4a66b97fd7e52e69c5be7b10bdc5341bded817201b9b7136a75068d4e4e0560403392a3005b837ff717901b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b5f80fd5b34610411576060600319360112610411576004356104316128b0565b610439612911565b90610442613147565b825f52600c60205260ff600160405f20015460c81c16156104c05761048c83927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce792602095613fe5565b939092604051908152a1604080516fffffffffffffffffffffffffffffffff928316815292909116602083015290f35b0390f35b827fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346104115760c06003193601126104115761050561289a565b61050d6128b0565b90610516612911565b9161051f6128dc565b9161052861296a565b60a435936fffffffffffffffffffffffffffffffff85168503610411576020956105649461055d94610558613147565b6136e3565b9182613597565b604051908152f35b34610411575f6003193601126104115760206001600160a01b035f5416604051908152f35b34610411576040600319360112610411576004356105ad6128f2565b6105b5613147565b815f52600c60205260ff600160405f20015460c81c161561069c57815f52600c60205260ff600160405f20015460d81c1661067057815f52600c6020526001600160a01b03600160405f20015416330361064057816106376020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79461350e565b604051908152a1005b507fa9ad2a22000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b507f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b507fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c602052602064ffffffffff600160405f20015460a01c16604051908152f35b7fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610411576040600319360112610411576004356107616128b0565b610769613147565b815f52600c60205260ff600160405f20015460c81c161561069c57907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce761048c6020936107b58461369f565b9084613fe5565b34610411576040600319360112610411576107d561289a565b6001600160a01b036107e56128b0565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c60205260206001600160a01b03600260405f20015416604051908152f35b34610411576020600319360112610411576020610884600435612d45565b6fffffffffffffffffffffffffffffffff60405191168152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a57805f52600c60205260405f205460801c156108ed57610564602091612fc0565b7f167274c9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461041157602060031936011261041157600435610935816130b9565b505f6001600160a01b0360095416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610a1f575f906109a2575b6104bc90604051918291602083526020830190612857565b503d805f833e6109b28183612996565b8101906020818303126104115780519067ffffffffffffffff821161041157019080601f83011215610411578151916109ea836129d7565b916109f86040519384612996565b83835260208483010111610411576104bc92610a1a9160208085019101612836565b61098a565b6040513d5f823e3d90fd5b346104115760c060031936011261041157600435610a466128f2565b610a4e6128c6565b610a566128dc565b60407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011261041157610a88613147565b835f52600c60205260ff600160405f20015460c81c1615610c5357835f52600c60205260ff600160405f20015460d81c16610c2757610ac79184613eda565b604051916040830183811067ffffffffffffffff821117610bfa576040526084356001600160a01b038116810361041157835260a435602084019080825267016345785d8a00008111610bc357506001600160a01b0384511615610b9b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793610b64610b5b6020956106379451906145df565b85929192613597565b835f52600c85526fffffffffffffffffffffffffffffffff6001600160a01b0380600260405f200154169351169116913390614429565b7f5f946a02000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f54b392b2000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b837f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b837fe21c1431000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c602052602060405f205460801c15604051908152f35b3461041157604060031936011261041157600435610ce46128f2565b610cec613147565b815f52600c60205260ff600160405f20015460c81c161561069c57815f52600c60205260405f205460801c15610d7257815f52600c6020526001600160a01b03600160405f2001541633036106405781610d696020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794613597565b610637816133da565b507f167274c9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a57610564602091613ea0565b34610411575f60031936011261041157602060405167016345785d8a00008152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c60205260206001600160a01b03600160405f20015416604051908152f35b34610411576020600319360112610411576004355f52600c602052602060ff600160405f20015460c81c166040519015158152f35b3461041157608060031936011261041157610e9961289a565b610ea16128b0565b6064359167ffffffffffffffff8311610411573660238401121561041157826004013591610ece836129d7565b92610edc6040519485612996565b8084523660248287010111610411576020815f926024610f089801838801378501015260443591612dd4565b005b34610411576020600319360112610411576001600160a01b03610f2b61289a565b165f52600a602052602060405f2054604051908152f35b3461041157608060031936011261041157600435610f5e6128f2565b610f666128c6565b610f6e6128dc565b90610f77613147565b835f52600c60205260ff600160405f20015460c81c1615610c5357835f52600c60205260ff600160405f20015460d81c16610c2757602092610fdf8593610637937ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce797613eda565b82613597565b3461041157604060031936011261041157610ffe61289a565b602435906001600160a01b035f54163381036103e2575067016345785d8a00008211611108576001600160a01b031690815f52600a60205260405f205490825f52600a6020528060405f205560405191825260208201527f371789a3d97098f3070492613273a065a7e8a19e009fd1ae92a4b4d4c71ed62d60403392a36008547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116110db5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b507f34553172000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c602052602060ff600160405f20015460d01c166040519015158152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a576111c890612d79565b60405160058210156111db576020918152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b34610411576040600319360112610411576004356112246128f2565b61122c613147565b815f52600c60205260ff600160405f20015460c81c161561069c57815f52600c60205260405f205460801c15610d7257815f52600c6020526001600160a01b03600160405f2001541633036106405781807ffddf01d0842635e80929251f6862b3baf136a29f2b2fb148968e8b236d5785fe60606020947ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7965f52600c86526fffffffffffffffffffffffffffffffff60405f205460801c916112ef8187613d6f565b6112f886613105565b9260405193845288840152166040820152a2604051908152a1005b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c602052602060ff600260405f20015460a01c16604051908152f35b346104115760406003193601126104115761137a61289a565b60243590811515809203610411576001600160a01b031690811561140757335f52600660205260405f20825f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610411575f600319360112610411576040515f6002548060011c90600181168015611568575b60208310811461153b578285529081156114f9575060011461149b575b6104bc8361148781850382612996565b604051918291602083526020830190612857565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106114df57509091508101602001611487611477565b9192600181602092548385880101520191019092916114c7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506114879050611477565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f169161145a565b34610411576020600319360112610411576004355f61012060405161159681612979565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201520152805f52600c60205260ff600160405f20015460c81c161561071a575f52600c60205260405f206040516115fe81612979565b81546fffffffffffffffffffffffffffffffff811692838352602083019160801c82526001810154604084016001600160a01b0382168152606085018260a01c64ffffffffff16815260808601908360c81c60ff161515825260a08701928460d01c60ff161515845260c088019460d81c60ff161515855260028601549660e08901966001600160a01b03891688526101008a019860a01c60ff168952600301549861012001988952604051998a52516fffffffffffffffffffffffffffffffff1660208a0152516001600160a01b031660408901525164ffffffffff166060880152511515608087015251151560a086015251151560c0850152516001600160a01b031660e08401525160ff166101008301525161012082015261014090f35b346104115760406003193601126104115760043561173b6128f2565b611743613147565b815f52600c60205260ff600160405f20015460c81c161561069c57815f52600c6020526001600160a01b03600160405f20015416330361064057816106376020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794613205565b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c602052602060405f205460801c604051908152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a57610564602091613d1f565b34610411576020600319360112610411576004356001600160a01b038116809103610411576001600160a01b035f54163381036103e2575060095490807fffffffffffffffffffffffff00000000000000000000000000000000000000008316176009556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26008547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81019081116110db5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b346104115760206003193601126104115761194461289a565b5f546001600160a01b0381163381036103e257506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b34610411576020600319360112610411576001600160a01b036119d261289a565b1680156119ef575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600360205260206001600160a01b0360405f205416604051908152f35b3461041157604060031936011261041157611a8261289a565b611a8a6128b0565b6001600160a01b035f54163381036103e257506001600160a01b038216916040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481875afa8015610a1f575f90611b8e575b611b029150845f52600760205260405f205490612d6c565b908115611b625781611b397f21252411d5a999da4bc6a490f7143b61ba690edceb4577a2800eab8dfbb1e92c9385611b5d94613cc3565b604051918291339583602090939291936001600160a01b0360408201951681520152565b0390a3005b837ff4c3afcf000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506020813d602011611bba575b81611ba860209383612996565b8101031261041157611b029051611aea565b3d9150611b9b565b34610411576020600319360112610411576020611be06004356130b9565b6001600160a01b0360405191168152f35b34610411576020600319360112610411576001600160a01b03611c1261289a565b165f526007602052602060405f2054604051908152f35b3461041157602060031936011261041157600435611c45613147565b805f52600c60205260ff600160405f20015460c81c161561071a57805f52600c60205260ff600160405f20015460d81c16611ed157805f52600c6020526001600160a01b03600160405f2001541633141580611ec1575b611e9257602081611ccd7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce793613ea0565b80611e4257611cdb82613d1f565b80611e21575b505b5f828152600c84526040902060010180547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff164260a01b78ffffffffff000000000000000000000000000000000000000016179055815f52600c835260405f206fffffffffffffffffffffffffffffffff8154169055815f52600c8352600160405f20017b010000000000000000000000000000000000000000000000000000007fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff825416179055815f52600c83526001600160a01b03600160405f20015416825f5260038452827fa8e3d71a6c0c719305004b430f6d17f12536f7b803db23a4d7016f5b52699a8c60606001600160a01b0360405f20541694611e0684613105565b9060405191338352898301526040820152a4604051908152a1005b825f52600c8452611e3a600360405f2001918254612f7c565b905584611ce1565b815f52600c8352611e7e6fffffffffffffffffffffffffffffffff60405f205416835f52600c855260ff600260405f20015460a01c1690613fcc565b825f52600c8452600360405f200155611ce3565b7fa9ad2a22000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b50611ecb816144df565b15611c9c565b7f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346104115760a0600319360112610411576020610564611f1a61289a565b611f226128b0565b611f2a612911565b611f326128dc565b91611f3b61296a565b93610558613147565b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c602052602060ff600160405f20015460d81c166040519015158152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c6020526020600360405f200154604051908152f35b34610411575f6003193601126104115760206001600160a01b0360095416604051908152f35b3461041157610f0861201336612930565b9060405192612023602085612996565b5f8452612dd4565b34610411576040600319360112610411576004356120476128f2565b61204f613147565b815f52600c60205260ff600160405f20015460c81c161561069c57815f52600c60205260405f205460801c15610d7257815f52600c6020526001600160a01b03600160405f2001541633036106405781610d696020927ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce794613205565b3461041157610f086120dd36612930565b91612a62565b34610411576060600319360112610411576004356120ff6128f2565b612107612911565b90612110613147565b825f52600c60205260ff600160405f20015460c81c16156104c057825f52600c60205260ff600160405f20015460d81c166121c657825f52600c6020526001600160a01b03600160405f2001541633036121965791610637602092610fdf7ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7958461350e565b827fa9ad2a22000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b827f7354d5f1000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610411575f600319360112610411576020600854604051908152f35b346104115760206003193601126104115760043567ffffffffffffffff8111610411573660238201121561041157806004013567ffffffffffffffff8111610411573660248260051b8401011161041157905f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd81360301915b83811015610f085760248160051b830101358381121561041157820160248101359067ffffffffffffffff821161041157604401813603811361041157815f92918392604051928392833781018381520390305af46122e7612a33565b90156122f6575060010161228a565b612334906040519182917fd9354485000000000000000000000000000000000000000000000000000000008352602060048401526024830190612857565b0390fd5b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a575f52600c60205260206fffffffffffffffffffffffffffffffff60405f205416604051908152f35b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a576108846020916131d3565b34610411576020600319360112610411576004356123e5613147565b805f52600c60205260ff600160405f20015460c81c161561071a57805f52600c60205260405f205460801c156108ed57805f52600c6020526001600160a01b03600160405f200154163303611e92576020816106377ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7936133da565b346104115760206003193601126104115760043561247d613147565b805f52600c60205260ff600160405f20015460c81c161561071a57805f52600c6020526001600160a01b03600160405f200154163303611e92576020816106376124e77ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7946131d3565b82613205565b34610411576020600319360112610411576001600160a01b0361250e61289a565b165f52600b60205260206fffffffffffffffffffffffffffffffff60405f205416604051908152f35b346104115760406003193601126104115761255061289a565b60243561255c816130b9565b33151580612641575b8061260e575b6125e25781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091167fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054161561256b565b50336001600160a01b0382161415612565565b3461041157602060031936011261041157600435805f52600c60205260ff600160405f20015460c81c161561071a57610564602091613105565b34610411576020600319360112610411576020611be0600435612a11565b34610411575f600319360112610411576040515f6001548060011c9060018116801561275d575b60208310811461153b578285529081156114f957506001146126ff576104bc8361148781850382612996565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061274357509091508101602001611487611477565b91926001816020925483858801015201910190929161272b565b91607f16916126d3565b3461041157602060031936011261041157600435907fffffffff00000000000000000000000000000000000000000000000000000000821680920361041157817f80ac58cd000000000000000000000000000000000000000000000000000000006020931490811561280c575b81156127e2575b5015158152f35b7f01ffc9a700000000000000000000000000000000000000000000000000000000915014836127db565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506127d4565b5f5b8381106128475750505f910152565b8181015183820152602001612838565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60209361289381518092818752878088019101612836565b0116010190565b600435906001600160a01b038216820361041157565b602435906001600160a01b038216820361041157565b604435906001600160a01b038216820361041157565b606435906001600160a01b038216820361041157565b602435906fffffffffffffffffffffffffffffffff8216820361041157565b604435906fffffffffffffffffffffffffffffffff8216820361041157565b6003196060910112610411576004356001600160a01b038116810361041157906024356001600160a01b0381168103610411579060443590565b60843590811515820361041157565b610140810190811067ffffffffffffffff821117610bfa57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610bfa57604052565b67ffffffffffffffff8111610bfa57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b612a1a816130b9565b505f5260056020526001600160a01b0360405f20541690565b3d15612a5d573d90612a44826129d7565b91612a526040519384612996565b82523d5f602084013e565b606090565b91906001600160a01b0316918215612d1957815f5260036020526001600160a01b0360405f205416151580612cfc575b612cd057815f5260036020526001600160a01b0360405f2054169233151580612c08575b50907ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce760206001600160a01b039386612b9b575b805f526004825260405f2060018154019055855f526003825260405f20817fffffffffffffffffffffffff00000000000000000000000000000000000000008254161790558560405191887fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4858152a116808303612b6a57505050565b7f64283d7b000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b612bd2865f52600560205260405f207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b865f526004825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055612aea565b80612c79575b15612c19575f612ab6565b8284612c4a577f7e273289000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612ca7575b80612c0e5750825f526005602052336001600160a01b0360405f20541614612c0e565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612c84565b507f7da2ea2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50815f52600c60205260ff600160405f20015460d01c1615612a92565b7f64a0ae92000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b805f52600c60205260ff600160405f20015460c81c161561071a57612d699061369f565b90565b919082039182116110db57565b805f52600c60205260ff600160405f20015460d81c16612dce57612d9c81613ea0565b1515905f52600c60205260405f205460801c15612dc057612dbb575f90565b600190565b612dc957600290565b600390565b50600490565b90612de0838284612a62565b803b612ded575b50505050565b602091612e4c6001600160a01b038093169560405195869485947f150b7a020000000000000000000000000000000000000000000000000000000086523360048701521660248501526044840152608060648401526084830190612857565b03815f865af15f9181612f1f575b50612ea15750612e68612a33565b80519081612e9c57827f64a0ae92000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602001fd5b7fffffffff000000000000000000000000000000000000000000000000000000007f150b7a0200000000000000000000000000000000000000000000000000000000911603612ef457505f808080612de7565b7f64a0ae92000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091506020813d602011612f74575b81612f3b60209383612996565b8101031261041157517fffffffff000000000000000000000000000000000000000000000000000000008116810361041157905f612e5a565b3d9150612f2e565b919082018092116110db57565b8115612f93570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b805f52600c6020526fffffffffffffffffffffffffffffffff60405f2054169081156130b357805f52600c60205261300660ff600260405f20015460a01c168093613fcc565b91815f52600c602052613020600360405f20015491613faf565b9061303361302d84613d1f565b82612f7c565b61303d8386612f7c565b11156130ab57825f52600c60205260405f205460801c930301916130618184612f89565b928115612f93570661308a575f52600c60205264ffffffffff600160405f20015460a01c160190565b906001915f52600c60205264ffffffffff8260405f20015460a01c16010190565b505050505f90565b50505f90565b805f5260036020526001600160a01b0360405f2054169081156130da575090565b7f7e273289000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d699061312b61311582613d1f565b825f52600c602052600360405f20015490612f7c565b905f52600c60205260ff600260405f20015460a01c1690614409565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361317957565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b906fffffffffffffffffffffffffffffffff809116911603906fffffffffffffffffffffffffffffffff82116110db57565b612d6990805f52600c6020526131ff6fffffffffffffffffffffffffffffffff60405f2054169161369f565b906131a1565b6fffffffffffffffffffffffffffffffff821680156133ae576fffffffffffffffffffffffffffffffff613238836131d3565b1680821161337c57825f52600c6020526fffffffffffffffffffffffffffffffff60405f2054161061332a5760207fe31f2d40d5780915b1e656a67e11bdf09b0a4a925ec42bbeae220c8ca937ab4991835f52600c8252613321816001600160a01b03600160405f200154168097875f52600c86526001600160a01b03600260405f2001541690885f52600c87526fffffffffffffffffffffffffffffffff8060405f2092818454160316167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055805f526007865260405f20838154039055613cc3565b604051908152a3565b90805f52600c6020526fffffffffffffffffffffffffffffffff60405f205416907fcb5f605f000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b917fe9771401000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b507fea66b871000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b805f52600c60205260405f205460801c156134df576133f881613d1f565b806134bd575b505f818152600c6020908152604080832060018101805478ffffffffff00000000000000000000000000000000000000004260a01b167fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff82161790915581546fffffffffffffffffffffffffffffffff16909155600383529220546001600160a01b0390811693921691907fda83bf669c651406e02062769e01d14cccb5625ea685fd95e0e56d29597dac47906134b483613105565b604051908152a4565b815f52600c6020526134d7600360405f2001918254612f7c565b90555f6133fe565b7fd2657d5a000000000000000000000000000000000000000000000000000000005f526004525f60245260445ffd5b805f52600c60205260405f205460801c61356c5761352c8282613d6f565b6fffffffffffffffffffffffffffffffff604051921682527fc2a543cfadbf862642247e28711aaa30e3460384be5712be6557fee3384454fd60203393a3565b7fdc6fbbbc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b906fffffffffffffffffffffffffffffffff16908115613674575f818152600c60205260409020600281015481546fffffffffffffffffffffffffffffffff9081168501916001600160a01b03169082116110db57613646926fffffffffffffffffffffffffffffffff8693167fffffffffffffffffffffffffffffffff00000000000000000000000000000000825416179055805f52600760205260405f2082815401905530903390614429565b6040519182527fa06c1466b3c9751408a5ac337a2e8808e5ee0ceed1fd70635d041b21174eb6b460203393a3565b7f33f2df5a000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b805f52600c6020526fffffffffffffffffffffffffffffffff60405f2054169081156130b3576136ce90613105565b8082106136df57612d699150614483565b5090565b6001600160a01b039095949293919516908115613c9b576001600160a01b0316926040517f313ce567000000000000000000000000000000000000000000000000000000008152602081600481885afa8015610a1f575f90613c5e575b60ff9150169560128711613c32576008549687866040519261376184612979565b5f845260208401956fffffffffffffffffffffffffffffffff1695868152604085019088825260608601994264ffffffffff168b52608087016001815260a088019115159b8c835260c08901935f855260e08a019788526101008a019687526101208a01985f8a525f52600c60205260405f2099516fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168a547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016178a55516fffffffffffffffffffffffffffffffff1661387a908a906fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff0000000000000000000000000000000083549260801b169116179055565b9351600189018054955178ffffffffff000000000000000000000000000000000000000060a09190911b166001600160a01b039092167fffffffffffffff00000000000000000000000000000000000000000000000000909616959095171784555115159083549051151560d01b7aff0000000000000000000000000000000000000000000000000000169160c81b79ff0000000000000000000000000000000000000000000000000016907fffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff161717825551151581549060d81b7bff00000000000000000000000000000000000000000000000000000016907fffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffff161790556002840191516001600160a01b03166001600160a01b031682547fffffffffffffffffffffffff0000000000000000000000000000000000000000161782555181549060a01b74ff000000000000000000000000000000000000000016907fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16179055519060030155600187016008556001600160a01b0316928315612d1957865f5260036020526001600160a01b0360405f205416151580613c15575b613be957865f5260036020526001600160a01b0360405f2054167ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce760208215159283613b7c575b875f526004825260405f20600181540190558a5f526003825260405f20887fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055604051908b89827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a4508a8152a1613b50577f2262fa211f8507786a60fefb231f7898b8145fe16350f281c91f121bd2ee118d916060916040519189835260208301526040820152a4565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b613bb38b5f52600560205260405f207fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055565b805f526004825260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8154019055613a9e565b867f7da2ea2b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50865f52600c60205260ff600160405f20015460d01c1615613a57565b847fc9f55392000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506020813d602011613c93575b81613c7860209383612996565b81010312610411575160ff811681036104115760ff90613740565b3d9150613c6b565b7ff9bb0fb3000000000000000000000000000000000000000000000000000000005f5260045ffd5b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000060208201526001600160a01b03929092166024830152604480830193909352918152613d1d91613d18606483612996565b614551565b565b5f908152600c602052604090206001810154905460801c9060a01c64ffffffffff1681158015613d65575b6130b357804203918083029283041490421417156110db5790565b5080421115613d4a565b91906fffffffffffffffffffffffffffffffff811692805f52600c60205260405f205460801c8414613e7057613d1d929350613daa81613d1f565b80613e4e575b505f908152600c6020526040902060018101805478ffffffffff00000000000000000000000000000000000000004260a01b167fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff90911617905580546fffffffffffffffffffffffffffffffff1660809290921b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016919091179055565b815f52600c602052613e68600360405f2001918254612f7c565b90555f613db0565b83907fd2657d5a000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b805f52600c602052613ec86fffffffffffffffffffffffffffffffff60405f20541691613105565b90818110156130b357612d6991612d6c565b90815f52600c6020526001600160a01b0380600160405f200154169116908103613f675750805f5260036020526001600160a01b038060405f2054169216918203613f23575050565b5f5260036020526001600160a01b0360405f205416907f5bdb8ad7000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b905f52600c6020526001600160a01b03600160405f20015416907fc8bac88d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b601260ff821614613fc65760120360ff16600a0a90565b50600190565b90601260ff8216146136df5760120360ff16600a0a0290565b5f9392916fffffffffffffffffffffffffffffffff83169182156143de576001600160a01b0382169182156143b257815f5260036020526001600160a01b0360405f205416831415806143a2575b61436f57815f52600c60205260ff600260405f20015460a01c169361407061405a84613d1f565b845f52600c602052600360405f20015490612f7c565b61407a8682614409565b95845f52600c6020526fffffffffffffffffffffffffffffffff60405f205416928784105f14614350576fffffffffffffffffffffffffffffffff845b1680821161431d5750906140ca91613fcc565b90845f52600c602052600360405f2001548211155f146142ba5750835f52600c602052600360405f20019081540390555b5f838152600c6020908152604080832080546fffffffffffffffffffffffffffffffff8082168c9003167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116178155600201546001600160a01b0316808452600a909252909120549095908061424c575b506141cc6141b66fffffffffffffffffffffffffffffffff926141a7848b1680978b5f52600760205260405f208281540390558b613cc3565b6141b087613105565b90612d6c565b92855f52600c6020528260405f205416906131a1565b160361421f5760607f1a7b0d6c8f96b874563b711cf97793fe3be5dc42dbd1e0720ce40f326918e817916040519033825260208201526fffffffffffffffffffffffffffffffff89166040820152a49190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b6141b699506142706141cc916fffffffffffffffffffffffffffffffff93996145df565b9a909a988b895f52600b602052848060405f2092818454160116167fffffffffffffffffffffffffffffffff0000000000000000000000000000000082541617905592505061416e565b5f858152600c60205260409020919003600382015560010180547fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff164260a01b78ffffffffff0000000000000000000000000000000000000000161790556140fb565b90867ff9f29859000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b6fffffffffffffffffffffffffffffffff61436a89614483565b6140b7565b507f4208ab4c000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b506143ac826144df565b15614033565b507f9f32c858000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fb4855052000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b90601260ff8216146136df579060ff612d699260120316600a0a90612f89565b9091926001600160a01b03613d1d9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252613d18608483612996565b6fffffffffffffffffffffffffffffffff81116144af576fffffffffffffffffffffffffffffffff1690565b7f6dfcc650000000000000000000000000000000000000000000000000000000005f52608060045260245260445ffd5b805f5260036020526001600160a01b0360405f20541690813314918215614525575b50811561450c575090565b90506001600160a01b036145203392612a11565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614501565b5f806001600160a01b0361457a93169360208151910182865af1614573612a33565b9083614729565b80519081151591826145bb575b50506145905750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126104115760200151801590811503610411575f80614587565b91906145fd906fffffffffffffffffffffffffffffffff841661465c565b6fffffffffffffffffffffffffffffffff8111614631576fffffffffffffffffffffffffffffffff612d69911680936131a1565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8382098382029182808310920391808303921461471857670de0b6b3a76400008210156146e8577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90614766575080511561473e57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806147ac575b614777575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561476f56fea164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557610ae4908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c63e9dc637514610024575f80fd5b346107d65760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126107d65760043573ffffffffffffffffffffffffffffffffffffffff8116036107d6576107cd604061073c61059561044061008c845191826107fb565b61041c81527f3c7376672077696474683d2235303022206865696768743d223530302220737460208201527f796c653d226261636b67726f756e642d636f6c6f723a20233134313631463b22848201527f20786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f7360608201527f7667222076696577426f783d223230202d343030203230302031303030223e3c60808201527f706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c2d60a08201527f6f7061636974793d22312220643d226d3133332e3535392c3132342e3033346360c08201527f2d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c362e60e08201527f3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e38386101008201527f382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e35366101208201527f352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3833386101408201527f2d312e3237322d32362e3332382d332e3636332d392e3830362d322e3736362d6101608201527f31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e38346101808201527f322d382e3032352c392e3436382d32382e3630362c31362e3135332d33352e326101a08201527f3635683063322e3033352d312e3833382c342e3235322d332e3534362c362e346101c08201527f36332d352e323234683063362e3432392d352e3635352c31362e3231382d322e6101e08201527f3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e38316102008201527f362c392e3634392c31332e39322c31332e373334682e30333763352e3733362c6102208201527f362e3436312c31352e3335372d322e3235332c392e33382d382e34382c302c306102408201527f2d332e3531352d332e3531352d332e3531352d332e3531352d31312e34392d316102608201527f312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e38336102808201527f376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731392d336102a08201527f2e3834372d322e3735312d362e3230346830632d2e3034362d322e3337352c316102c08201527f2e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d2e316102e08201527f34386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e32356103008201527f39683063322e30362d312e3336322c332e3935312d322e3632312c362e3034346103208201527f2d332e3834324335372e3736332d332e3437332c39372e37362d322e3334312c6103408201527f3132382e3633372c31382e3333326331362e3637312c392e3934362d32362e336103608201527f34342c35342e3831332d33382e3635312c34302e3139392d362e3239392d362e6103808201527f3039362d31382e3036332d31372e3734332d31392e3636382d31382e3831312d6103a08201527f362e3031362d342e3034372d31332e3036312c342e3737362d372e3735322c396103c08201527f2e3735316c36382e3235342c36382e33373163312e3732342c312e3630312c326103e08201527f2e3731342c332e38342c322e3733382c362e3139325a22207472616e73666f726104008201527f6d3d227363616c6528312e352c20312e352922202f3e3c2f7376673e000000006104208201526108a3565b610737600260c8855180947f7b226465736372697074696f6e223a202254686973204e46542072657072657360208301527f656e74732061207061796d656e742073747265616d20696e205361626c696572888301527f20466c6f77222c0000000000000000000000000000000000000000000000000060608301527f2265787465726e616c5f75726c223a202268747470733a2f2f7361626c69657260678301527f2e636f6d222c000000000000000000000000000000000000000000000000000060878301527f226e616d65223a20225361626c69657220466c6f77222c000000000000000000608d8301527f22696d616765223a2022646174613a696d6167652f7376672b786d6c3b62617360a48301527f6536342c0000000000000000000000000000000000000000000000000000000060c48301526106e281518092602086860191016107da565b81017f227d0000000000000000000000000000000000000000000000000000000000008382015203017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe28101845201826107fb565b6108a3565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8351926107b2603d8560208101937f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c00000085526107a381518092602086860191016107da565b810103018481018652856107fb565b845195869460208652518092816020880152878701906107da565b01168101030190f35b5f80fd5b5f5b8381106107eb5750505f910152565b81810151838201526020016107dc565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761083c57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b67ffffffffffffffff811161083c57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b90815115610ac157604051916108ba6060846107fb565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111610a945760039004908160021b917f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811603610a945761096b61095583610869565b9261096360405194856107fb565b808452610869565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06020840191013682379080815182019560208701908151925f83525b888110610a4657505060039394959650525106806001146109f7576002146109ce575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff603d91015390565b507ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81603d7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81940153015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c16870101516002850153168401015160038201530194976109a8565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b9050604051610ad16020826107fb565b5f81529056fea164736f6c634300081a000a"; diff --git a/src/SablierFlow.sol b/src/SablierFlow.sol index 55c4103d..2495e0d8 100644 --- a/src/SablierFlow.sol +++ b/src/SablierFlow.sol @@ -363,6 +363,21 @@ contract SablierFlow is _pause(streamId); } + /// @inheritdoc ISablierFlow + function refundMax(uint256 streamId) + external + override + noDelegateCall + notNull(streamId) + onlySender(streamId) + updateMetadata(streamId) + { + uint128 refundableAmount = _refundableAmountOf(streamId); + + // Checks, Effects, and Interactions: make the refund. + _refund(streamId, refundableAmount); + } + /// @inheritdoc ISablierFlow function restart( uint256 streamId, diff --git a/src/interfaces/ISablierFlow.sol b/src/interfaces/ISablierFlow.sol index 8ba0a3c4..2129f731 100644 --- a/src/interfaces/ISablierFlow.sol +++ b/src/interfaces/ISablierFlow.sol @@ -340,6 +340,16 @@ interface ISablierFlow is /// @param amount The amount to refund, denoted in token's decimals. function refundAndPause(uint256 streamId, uint128 amount) external; + /// @notice Refunds the entire refundable amount of tokens from the stream to the sender's address. + /// + /// @dev Emits {Transfer} and {RefundFromFlowStream} events. + /// + /// Requirements: + /// - Refer to the notes in {refund}. + /// + /// @param streamId The ID of the stream to refund from. + function refundMax(uint256 streamId) external; + /// @notice Restarts the stream with the provided rate per second. /// /// @dev Emits {RestartFlowStream} event. diff --git a/tests/integration/concrete/refund-max/refundMax.t.sol b/tests/integration/concrete/refund-max/refundMax.t.sol new file mode 100644 index 00000000..97093e8a --- /dev/null +++ b/tests/integration/concrete/refund-max/refundMax.t.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierFlow } from "src/interfaces/ISablierFlow.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract RefundMax_Integration_Concrete_Test is Integration_Test { + function setUp() public override { + Integration_Test.setUp(); + + // Deposit to the default stream. + depositToDefaultStream(); + } + + function test_RevertWhen_DelegateCall() external { + bytes memory callData = abi.encodeCall(flow.refundMax, (defaultStreamId)); + expectRevert_DelegateCall(callData); + } + + function test_RevertGiven_Null() external whenNoDelegateCall { + bytes memory callData = abi.encodeCall(flow.refundMax, (nullStreamId)); + expectRevert_Null(callData); + } + + function test_RevertWhen_CallerRecipient() external whenNoDelegateCall givenNotNull whenCallerNotSender { + bytes memory callData = abi.encodeCall(flow.refundMax, (defaultStreamId)); + expectRevert_CallerRecipient(callData); + } + + function test_RevertWhen_CallerMaliciousThirdParty() external whenNoDelegateCall givenNotNull whenCallerNotSender { + bytes memory callData = abi.encodeCall(flow.refundMax, (defaultStreamId)); + expectRevert_CallerMaliciousThirdParty(callData); + } + + function test_GivenPaused() external whenNoDelegateCall givenNotNull whenCallerSender { + flow.pause(defaultStreamId); + + // It should make the refund. + _test_RefundMax({ streamId: defaultStreamId, token: usdc, depositedAmount: DEPOSIT_AMOUNT_6D }); + } + + function test_GivenNotPaused() external whenNoDelegateCall givenNotNull whenCallerSender { + // It should make the refund. + _test_RefundMax({ streamId: defaultStreamId, token: usdc, depositedAmount: DEPOSIT_AMOUNT_6D }); + } + + function _test_RefundMax(uint256 streamId, IERC20 token, uint128 depositedAmount) private { + uint256 previousAggregateAmount = flow.aggregateBalance(token); + uint128 refundableAmount = flow.refundableAmountOf(streamId); + + // It should emit 1 {Transfer}, 1 {RefundFromFlowStream}, 1 {MetadataUpdate} events. + vm.expectEmit({ emitter: address(token) }); + emit IERC20.Transfer({ from: address(flow), to: users.sender, value: refundableAmount }); + + vm.expectEmit({ emitter: address(flow) }); + emit ISablierFlow.RefundFromFlowStream({ streamId: streamId, sender: users.sender, amount: refundableAmount }); + + vm.expectEmit({ emitter: address(flow) }); + emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + + // It should perform the ERC-20 transfer. + expectCallToTransfer({ token: token, to: users.sender, amount: refundableAmount }); + flow.refundMax(streamId); + + // It should update the stream balance. + uint128 actualStreamBalance = flow.getBalance(streamId); + uint128 expectedStreamBalance = depositedAmount - refundableAmount; + assertEq(actualStreamBalance, expectedStreamBalance, "stream balance"); + + // It should decrease the aggregate amount. + assertEq(flow.aggregateBalance(token), previousAggregateAmount - refundableAmount, "aggregate amount"); + } +} diff --git a/tests/integration/concrete/refund-max/refundMax.tree b/tests/integration/concrete/refund-max/refundMax.tree new file mode 100644 index 00000000..dfa12585 --- /dev/null +++ b/tests/integration/concrete/refund-max/refundMax.tree @@ -0,0 +1,21 @@ +RefundMax_Integration_Concrete_Test +├── when delegate call +│ └── it should revert +└── when no delegate call + ├── given null + │ └── it should revert + └── given not null + ├── when caller not sender + │ ├── when caller recipient + │ │ └── it should revert + │ └── when caller malicious third party + │ └── it should revert + └── when caller sender + ├── given paused + │ └── it should make the refund + └── given not paused + ├── it should make the refund + ├── it should update the stream balance + ├── it should decrease the aggregate amount + ├── it should perform the ERC20 transfer + └── it should emit 1 {Transfer}, 1 {RefundFromFlowStream}, 1 {MetadataUpdate} event diff --git a/tests/integration/fuzz/refundMax.t.sol b/tests/integration/fuzz/refundMax.t.sol new file mode 100644 index 00000000..86345fc9 --- /dev/null +++ b/tests/integration/fuzz/refundMax.t.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierFlow } from "src/interfaces/ISablierFlow.sol"; + +import { Shared_Integration_Fuzz_Test } from "./Fuzz.t.sol"; + +contract RefundMax_Integration_Fuzz_Test is Shared_Integration_Fuzz_Test { + /// @dev Checklist: + /// - It should refund the refundable amount of tokens from a stream. + /// - It should emit the following events: {Transfer}, {MetadataUpdate}, {RefundFromFlowStream} + /// + /// Given enough runs, all of the following scenarios should be fuzzed: + /// - Multiple streams to refund from, each with different token decimals and rate per second. + /// - Multiple points in time prior to depletion period. + function testFuzz_RefundMax( + uint256 streamId, + uint40 timeJump, + uint8 decimals + ) + external + whenNoDelegateCall + givenNotNull + { + (streamId,,) = useFuzzedStreamOrCreate(streamId, decimals); + + // Bound the time jump so that it is less than the depletion timestamp. + uint40 depletionPeriod = uint40(flow.depletionTimeOf(streamId)); + timeJump = boundUint40(timeJump, getBlockTimestamp(), depletionPeriod - 1); + + // Simulate the passage of time. + vm.warp({ newTimestamp: timeJump }); + + uint128 refundableAmount = flow.refundableAmountOf(streamId); + + // Ensure refundable amount is not zero. It could be zero for a small time range upto the depletion time due to + // precision error. + vm.assume(refundableAmount != 0); + + // Following variables are used during assertions. + uint256 initialAggregateAmount = flow.aggregateBalance(token); + uint256 initialTokenBalance = token.balanceOf(address(flow)); + uint128 initialStreamBalance = flow.getBalance(streamId); + + // Expect the relevant events to be emitted. + vm.expectEmit({ emitter: address(token) }); + emit IERC20.Transfer({ from: address(flow), to: users.sender, value: refundableAmount }); + + vm.expectEmit({ emitter: address(flow) }); + emit ISablierFlow.RefundFromFlowStream({ streamId: streamId, sender: users.sender, amount: refundableAmount }); + + vm.expectEmit({ emitter: address(flow) }); + emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + + // Request the maximum refund. + flow.refundMax(streamId); + + // Assert that the token balance of stream has been updated. + uint256 actualTokenBalance = token.balanceOf(address(flow)); + uint256 expectedTokenBalance = initialTokenBalance - refundableAmount; + assertEq(actualTokenBalance, expectedTokenBalance, "token balanceOf"); + + // Assert that stored balance in stream has been updated. + uint256 actualStreamBalance = flow.getBalance(streamId); + uint256 expectedStreamBalance = initialStreamBalance - refundableAmount; + assertEq(actualStreamBalance, expectedStreamBalance, "stream balance"); + + // Assert that the aggregate amount has been updated. + uint256 actualAggregateAmount = flow.aggregateBalance(token); + uint256 expectedAggregateAmount = initialAggregateAmount - refundableAmount; + assertEq(actualAggregateAmount, expectedAggregateAmount, "aggregate amount"); + } +}