diff --git a/.gitignore b/.gitignore index d3a2f57..b7e115d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ out/ coverage/ # Ignores development broadcast logs -!broadcast -broadcast/* broadcast/*/31337/ # Dotenv file diff --git a/broadcast/DeployModule.s.sol/100/run-1752838978.json b/broadcast/DeployModule.s.sol/100/run-1752838978.json new file mode 100644 index 0000000..63443ee --- /dev/null +++ b/broadcast/DeployModule.s.sol/100/run-1752838978.json @@ -0,0 +1,51 @@ +{ + "transactions": [ + { + "hash": "0xc6f3afbd71041b5462e98a3fe2d7f10673afaee4a46aedec8d1ca4a14c1eeba5", + "transactionType": "CREATE", + "contractName": "SubscriptionModule", + "contractAddress": "0x7f15133efc558a93173cd182818cdd6b44c84a74", + "function": null, + "arguments": null, + "transaction": { + "from": "0xff1725e448313743f3062fa963449ebae46dda18", + "gas": "0x2b8096", + "value": "0x0", + "input": "0x6080604052348015600e575f5ffd5b506126d48061001c5f395ff3fe608060405234801561000f575f5ffd5b50600436106100cf575f3560e01c8063a4c52b861161007d578063f7ff720711610058578063f7ff72071461021c578063f8c601461461022f578063ffa1ad7414610242575f5ffd5b8063a4c52b86146101ae578063b8c3a152146101ee578063f448a98d14610209575f5ffd5b8063321ac0ef116100ad578063321ac0ef146101315780635e03840914610144578063a3f4df7e14610165575f5ffd5b8063146d9194146100d35780631f32768e146100fc5780632cb4c27c1461011c575b5f5ffd5b6100e66100e1366004611b8b565b61027e565b6040516100f39190611ba4565b60405180910390f35b61010f61010a366004611be6565b6102b4565b6040516100f39190611c3e565b61012f61012a366004611cb6565b610387565b005b61012f61013f366004611d27565b6103c0565b610157610152366004611d51565b610496565b6040519081526020016100f3565b6101a16040518060400160405280601381526020017f537562736372697074696f6e204d6f64756c650000000000000000000000000081525081565b6040516100f39190611dc7565b6101c973c12c1e50abb450d6205ea2c3fa861b3b834d13e881565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f3565b6101c97338869bf66a61cf6bdb996a6ae40d5853fd43b52681565b610157610217366004611be6565b6105b8565b61012f61022a366004611dd9565b6106b2565b61012f61023d366004611be6565b610a0a565b6101a16040518060400160405280600581526020017f302e312e3000000000000000000000000000000000000000000000000000000081525081565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526001602052604090206060906102ae90610a17565b92915050565b6102e96040805160c0810182525f8082526020820181905291810182905260608101829052608081018290529060a082015290565b5f8281526020818152604091829020825160c081018452815473ffffffffffffffffffffffffffffffffffffffff90811682526001830154169281019290925260028082015493830193909352600381015460608301526004810154608083015260058101549192909160a084019160ff9091169081111561036d5761036d611bfd565b600281111561037e5761037e611bfd565b90525092915050565b5f5b818110156103bb576103b3338484848181106103a7576103a7611e50565b90506020020135610ad0565b600101610389565b505050565b5f828152602081905260409020600181015473ffffffffffffffffffffffffffffffffffffffff163314610420576040517fa1bfc65b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604051339085907fdc64f625b092a0e1f69a574cc4780a1e3c17ad6c6bff9756fd5606b7361fead6905f90a4505050565b5f5f83116104d0576040517fe3c2448f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c08101825233815273ffffffffffffffffffffffffffffffffffffffff871660208201529081018590525f906060810161050f8642611eaa565b815260200185815260200184600281111561052c5761052c611bfd565b9052905061053981610cc5565b91506105458282610cf4565b8573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16837f5ba2bd70fc00e95083121c56c84817a196474482b43591f04856084f8aeb362f8888886040516105a793929190611ebd565b60405180910390a450949350505050565b5f8181526020819052604081205473ffffffffffffffffffffffffffffffffffffffff166105e757505f919050565b5f82815260208181526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416938101939093526002808201549284019290925260038101546060840152600481015460808401526005810154909160a084019160ff169081111561066657610666611bfd565b600281111561067757610677611bfd565b815250509050806040015181608001518260600151426106979190611eaa565b6106a19190611ed8565b6106ab9190611f10565b9392505050565b5f83815260208181526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416938101939093526002808201549284019290925260038101546060840152600481015460808401526005810154909160a084019160ff169081111561073157610731611bfd565b600281111561074257610742611bfd565b905250805190915073ffffffffffffffffffffffffffffffffffffffff16610795576040517ee6a17000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81608001518260600151426107ab9190611eaa565b6107b59190611ed8565b905060018110156107f2576040517fc850188000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61082c8260400151826108059190611f10565b7f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e9090610e56565b608082015161083b9082611f10565b8260600181815161084c9190611f27565b9052505f85815260208181526040918290208451815473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161783559286015160018084018054929093169190941617905591840151600280840191909155606085015160038401556080850151600484015560a0850151600584018054879594929391927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911691849081111561092057610920611bfd565b0217905550600291506109309050565b8260a00151600281111561094657610946611bfd565b0361095a576109558583610e5d565b610a03565b5f8260a00151600281111561097157610971611bfd565b036109aa575f80808080610987888a018a612299565b945094509450945094506109a08a888787878787611102565b5050505050610a03565b60018260a0015160028111156109c2576109c2611bfd565b036109d1576109558583611470565b6040517fd67592f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b610a143382610ad0565b50565b6318fb58646004525f81815260249020801954604051919068fbb67fda52d4bfb8bf906020840181610a905783548015610a8a57808414150281526001848101549092508015610a8a57808414150260208201526002848101549092508015610a8a576003925083811415810260408301525b50610abb565b8160011c91505f5b82811015610ab957848101548481141502600582901b830152600101610a98565b505b8185528160051b810160405250505050919050565b5f81815260208181526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416938101939093526002808201549284019290925260038101546060840152600481015460808401526005810154909160a084019160ff1690811115610b4f57610b4f611bfd565b6002811115610b6057610b60611bfd565b8152505090508273ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff1614610bce576040517f2e9cd3ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526020818152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116825560018083018054909216909155600282018590556003820185905560048201859055600590910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055845173ffffffffffffffffffffffffffffffffffffffff1684529091529020610c7a90836116a7565b50805160405173ffffffffffffffffffffffffffffffffffffffff9091169083907f59332f9abbff096727b5f98534b0146dcab05c8a32ebce917a9fa6c66e7033a1905f90a3505050565b5f81604051602001610cd79190611c3e565b604051602081830303815290604052805190602001209050919050565b5f8281526020819052604090205473ffffffffffffffffffffffffffffffffffffffff1615610d4f576040517f066e20da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260208181526040918290208351815473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161783559285015160018084018054929093169190941617905591830151600280840191909155606084015160038401556080840151600484015560a0840151600584018054869594929391927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116918490811115610e2057610e20611bfd565b021790555050815173ffffffffffffffffffffffffffffffffffffffff165f9081526001602052604090206103bb9150836117ae565b80825d5050565b6040805160018082528183019092525f9160208083019080368337019050509050815f0151815f81518110610e9457610e94611e50565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101909101526040805160018082528183019092525f918160200160208202803683370190505090508260400151815f81518110610ef457610ef4611e50565b602002602001018181525050825f015173ffffffffffffffffffffffffffffffffffffffff1663468721a773c12c1e50abb450d6205ea2c3fa861b3b834d13e85f86602001518686604051602401610f4e93929190612407565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6cb498e500000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152610fe1939291905f90600401612487565b6020604051808303815f875af1158015610ffd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061102191906124dc565b611057576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015173ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff16857fbdbaf70d5ad57b002382ab2439f43339eb5034dcb891ec13621a3009033f3e61866080015187606001516110c29190611f27565b60405190815260200160405180910390a46110fc7f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e906118c9565b50505050565b855f015173ffffffffffffffffffffffffffffffffffffffff1685828151811061112e5761112e611e50565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614611183576040517f891d7c4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61118d83826118cf565b6111c3576040517fbb5c88e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208601516111d5908490878561191d565b61120b576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e905c61123685611a25565b1461126d576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855f015173ffffffffffffffffffffffffffffffffffffffff1663468721a773c12c1e50abb450d6205ea2c3fa861b3b834d13e85f888888886040516024016112b994939291906125bd565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d22d9b500000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261134c939291905f90600401612487565b6020604051808303815f875af1158015611368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061138c91906124dc565b6113c2576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856020015173ffffffffffffffffffffffffffffffffffffffff16865f015173ffffffffffffffffffffffffffffffffffffffff16887fbdbaf70d5ad57b002382ab2439f43339eb5034dcb891ec13621a3009033f3e6189608001518a6060015161142d9190611f27565b60405190815260200160405180910390a46114677f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e906118c9565b50505050505050565b80516020808301516040805173ffffffffffffffffffffffffffffffffffffffff94851660248201819052949092166044830152606482018490527f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e905c608483015260a060a48301525f60c48084018290528251808503909101815260e4909301825292820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff242432a00000000000000000000000000000000000000000000000000000000179052517f468721a700000000000000000000000000000000000000000000000000000000815263468721a7926115889273c12c1e50abb450d6205ea2c3fa861b3b834d13e8928290600401612487565b6020604051808303815f875af11580156115a4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c891906124dc565b6115fe576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806020015173ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff16837fbdbaf70d5ad57b002382ab2439f43339eb5034dcb891ec13621a3009033f3e61846080015185606001516116699190611f27565b60405190815260200160405180910390a46116a37f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e906118c9565b5050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf83036116d45763f5a267f15f526004601cfd5b826116e65768fbb67fda52d4bfb8bf92505b8019548061174f5760019250838254036117135760018201805483556002830180549091555f90556117a6565b836001830154036117315760028201805460018401555f90556117a6565b83600283015403611747575f60028301556117a6565b5f92506117a6565b81602052835f5260405f208054806117685750506117a6565b60018360011c03925082600182031461179257828401548060018303860155805f52508060405f20555b5060018260011b178319555f815550600192505b505092915050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf83036117db5763f5a267f15f526004601cfd5b826117ed5768fbb67fda52d4bfb8bf92505b80195481602052806118915781548061180d5784835560019350506117a6565b84810361181a57506117a6565b600183015480611835578560018501556001945050506117a6565b8581036118435750506117a6565b60028401548061185f57866002860155600195505050506117a6565b86810361186e575050506117a6565b5f9283526040808420600190559183528183206002905582529020600390555060075b835f5260405f2080546118c057600191821c8381018690558083019182905590821b82178319559092506117a6565b50505092915050565b5f815d50565b5f5f5b835181101561191357828482815181106118ee576118ee611e50565b60200260200101515f015161ffff161461190b575f9150506102ae565b6001016118d2565b5060019392505050565b5f5f856001875161192e9190611eaa565b8151811061193e5761193e611e50565b602002602001015190505f81602001515190505f5f90505b81811015611a15575f8360200151828151811061197557611975611e50565b602002602001015160066119899190612667565b611994906004612684565b61ffff1690505f6119b087836119ab816002611f27565b611aad565b90508873ffffffffffffffffffffffffffffffffffffffff168882815181106119db576119db611e50565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614611a0b575f95505050505050611a1d565b5050600101611956565b506001925050505b949350505050565b5f805b8251811015611aa757828181518110611a4357611a43611e50565b60200260200101515f015161ffff16600103611a9f57828181518110611a6b57611a6b611e50565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1682611a9c9190611f27565b91505b600101611a28565b50919050565b5f80611aba858585611afe565b90505f5b8151811015611af557818181518110611ad957611ad9611e50565b60209101015160f81c60089390931b9290921791600101611abe565b50509392505050565b60608351828111611b0d578092505b838111611b18578093505b50818310156106ab5750604051828203848401601f19601f830181165b8281015185820152810180611b35575050508060208301015f81526020810160405250808252509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611b86575f5ffd5b919050565b5f60208284031215611b9b575f5ffd5b6106ab82611b63565b602080825282518282018190525f918401906040840190835b81811015611bdb578351835260209384019390920191600101611bbd565b509095945050505050565b5f60208284031215611bf6575f5ffd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110611c3a57611c3a611bfd565b9052565b5f60c08201905073ffffffffffffffffffffffffffffffffffffffff835116825273ffffffffffffffffffffffffffffffffffffffff602084015116602083015260408301516040830152606083015160608301526080830151608083015260a0830151611caf60a0840182611c2a565b5092915050565b5f5f60208385031215611cc7575f5ffd5b823567ffffffffffffffff811115611cdd575f5ffd5b8301601f81018513611ced575f5ffd5b803567ffffffffffffffff811115611d03575f5ffd5b8560208260051b8401011115611d17575f5ffd5b6020919091019590945092505050565b5f5f60408385031215611d38575f5ffd5b82359150611d4860208401611b63565b90509250929050565b5f5f5f5f60808587031215611d64575f5ffd5b611d6d85611b63565b93506020850135925060408501359150606085013560038110611d8e575f5ffd5b939692955090935050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6106ab6020830184611d99565b5f5f5f60408486031215611deb575f5ffd5b83359250602084013567ffffffffffffffff811115611e08575f5ffd5b8401601f81018613611e18575f5ffd5b803567ffffffffffffffff811115611e2e575f5ffd5b866020828401011115611e3f575f5ffd5b939660209190910195509293505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156102ae576102ae611e7d565b8381526020810183905260608101611a1d6040830184611c2a565b5f82611f0b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b80820281158282048414176102ae576102ae611e7d565b808201808211156102ae576102ae611e7d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715611f8a57611f8a611f3a565b60405290565b6040516060810167ffffffffffffffff81118282101715611f8a57611f8a611f3a565b604051601f8201601f1916810167ffffffffffffffff81118282101715611fdc57611fdc611f3a565b604052919050565b5f67ffffffffffffffff821115611ffd57611ffd611f3a565b5060051b60200190565b803561ffff81168114611b86575f5ffd5b5f82601f830112612027575f5ffd5b813561203a61203582611fe4565b611fb3565b8082825260208201915060208360061b86010192508583111561205b575f5ffd5b602085015b838110156120cd5760408188031215612077575f5ffd5b61207f611f67565b61208882612007565b8152602082013577ffffffffffffffffffffffffffffffffffffffffffffffff811681146120b4575f5ffd5b6020828101919091529084529290920191604001612060565b5095945050505050565b5f82601f8301126120e6575f5ffd5b813567ffffffffffffffff81111561210057612100611f3a565b6121136020601f19601f84011601611fb3565b818152846020838601011115612127575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f830112612152575f5ffd5b813561216061203582611fe4565b8082825260208201915060208360051b860101925085831115612181575f5ffd5b602085015b838110156120cd57803567ffffffffffffffff8111156121a4575f5ffd5b86016060818903601f190112156121b9575f5ffd5b6121c1611f90565b6121cd60208301612007565b8152604082013567ffffffffffffffff8111156121e8575f5ffd5b82016020810190603f018a136121fc575f5ffd5b803561220a61203582611fe4565b8082825260208201915060208360051b85010192508c83111561222b575f5ffd5b6020840193505b828410156122545761224384612007565b825260209384019390910190612232565b6020850152505050606082013567ffffffffffffffff811115612275575f5ffd5b6122848a6020838601016120d7565b60408301525084525060209283019201612186565b5f5f5f5f5f60a086880312156122ad575f5ffd5b853567ffffffffffffffff8111156122c3575f5ffd5b8601601f810188136122d3575f5ffd5b80356122e161203582611fe4565b8082825260208201915060208360051b85010192508a831115612302575f5ffd5b6020840193505b8284101561232b5761231a84611b63565b825260209384019390910190612309565b9750505050602086013567ffffffffffffffff811115612349575f5ffd5b61235588828901612018565b945050604086013567ffffffffffffffff811115612371575f5ffd5b61237d88828901612143565b935050606086013567ffffffffffffffff811115612399575f5ffd5b6123a5888289016120d7565b95989497509295608001359392505050565b5f8151808452602084019350602083015f5b828110156123fd57815173ffffffffffffffffffffffffffffffffffffffff168652602095860195909101906001016123c9565b5093949350505050565b73ffffffffffffffffffffffffffffffffffffffff84168152608060208201525f61243560808301856123b7565b8281036040840152835180825260208086019201905f5b8181101561246a57835183526020938401939092019160010161244c565b505083810360608501525f81526020810192505050949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201525f6124bb6080830185611d99565b9050600283106124cd576124cd611bfd565b82606083015295945050505050565b5f602082840312156124ec575f5ffd5b815180151581146106ab575f5ffd5b5f82825180855260208501945060208160051b830101602085015f5b838110156125b157848303601f190188528151805161ffff168452602080820151606082870181905281519087018190529101905f9060808701905b8083101561257a5761ffff8451168252602082019150602084019350600183019250612553565b506040840151935086810360408801526125948185611d99565b965050505050602082019150602088019750600181019050612517565b50909695505050505050565b608081525f6125cf60808301876123b7565b82810360208401528086518083526020830191506020880192505f5b81811015612633578351805161ffff16845260209081015177ffffffffffffffffffffffffffffffffffffffffffffffff1681850152909301926040909201916001016125eb565b5050838103604085015261264781876124fb565b915050828103606084015261265c8185611d99565b979650505050505050565b61ffff8181168382160290811690818114611caf57611caf611e7d565b61ffff81811683821601908111156102ae576102ae611e7d56fea2646970667358221220b31c6eb74716542e5eee381275d609f5778bf96b7fe95b8ae16673e7038a214464736f6c634300081c0033", + "nonce": "0xa", + "chainId": "0x64" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x27da87", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xc6f3afbd71041b5462e98a3fe2d7f10673afaee4a46aedec8d1ca4a14c1eeba5", + "transactionIndex": "0x5", + "blockHash": "0xf85394133cc2433fc93aadc3f0fe01d507478b5fab4a846c4a26e33914c49502", + "blockNumber": "0x273e210", + "gasUsed": "0x21769b", + "effectiveGasPrice": "0x295", + "from": "0xff1725e448313743f3062fa963449ebae46dda18", + "to": null, + "contractAddress": "0x7f15133efc558a93173cd182818cdd6b44c84a74" + } + ], + "libraries": [], + "pending": [], + "returns": { + "module": { + "internal_type": "contract SubscriptionModule", + "value": "0x7f15133efC558a93173cD182818cdd6b44C84a74" + } + }, + "timestamp": 1752838978, + "chain": 100, + "commit": "1908d19" +} \ No newline at end of file diff --git a/broadcast/DeployModule.s.sol/100/run-latest.json b/broadcast/DeployModule.s.sol/100/run-latest.json new file mode 100644 index 0000000..63443ee --- /dev/null +++ b/broadcast/DeployModule.s.sol/100/run-latest.json @@ -0,0 +1,51 @@ +{ + "transactions": [ + { + "hash": "0xc6f3afbd71041b5462e98a3fe2d7f10673afaee4a46aedec8d1ca4a14c1eeba5", + "transactionType": "CREATE", + "contractName": "SubscriptionModule", + "contractAddress": "0x7f15133efc558a93173cd182818cdd6b44c84a74", + "function": null, + "arguments": null, + "transaction": { + "from": "0xff1725e448313743f3062fa963449ebae46dda18", + "gas": "0x2b8096", + "value": "0x0", + "input": "0x6080604052348015600e575f5ffd5b506126d48061001c5f395ff3fe608060405234801561000f575f5ffd5b50600436106100cf575f3560e01c8063a4c52b861161007d578063f7ff720711610058578063f7ff72071461021c578063f8c601461461022f578063ffa1ad7414610242575f5ffd5b8063a4c52b86146101ae578063b8c3a152146101ee578063f448a98d14610209575f5ffd5b8063321ac0ef116100ad578063321ac0ef146101315780635e03840914610144578063a3f4df7e14610165575f5ffd5b8063146d9194146100d35780631f32768e146100fc5780632cb4c27c1461011c575b5f5ffd5b6100e66100e1366004611b8b565b61027e565b6040516100f39190611ba4565b60405180910390f35b61010f61010a366004611be6565b6102b4565b6040516100f39190611c3e565b61012f61012a366004611cb6565b610387565b005b61012f61013f366004611d27565b6103c0565b610157610152366004611d51565b610496565b6040519081526020016100f3565b6101a16040518060400160405280601381526020017f537562736372697074696f6e204d6f64756c650000000000000000000000000081525081565b6040516100f39190611dc7565b6101c973c12c1e50abb450d6205ea2c3fa861b3b834d13e881565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f3565b6101c97338869bf66a61cf6bdb996a6ae40d5853fd43b52681565b610157610217366004611be6565b6105b8565b61012f61022a366004611dd9565b6106b2565b61012f61023d366004611be6565b610a0a565b6101a16040518060400160405280600581526020017f302e312e3000000000000000000000000000000000000000000000000000000081525081565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526001602052604090206060906102ae90610a17565b92915050565b6102e96040805160c0810182525f8082526020820181905291810182905260608101829052608081018290529060a082015290565b5f8281526020818152604091829020825160c081018452815473ffffffffffffffffffffffffffffffffffffffff90811682526001830154169281019290925260028082015493830193909352600381015460608301526004810154608083015260058101549192909160a084019160ff9091169081111561036d5761036d611bfd565b600281111561037e5761037e611bfd565b90525092915050565b5f5b818110156103bb576103b3338484848181106103a7576103a7611e50565b90506020020135610ad0565b600101610389565b505050565b5f828152602081905260409020600181015473ffffffffffffffffffffffffffffffffffffffff163314610420576040517fa1bfc65b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155604051339085907fdc64f625b092a0e1f69a574cc4780a1e3c17ad6c6bff9756fd5606b7361fead6905f90a4505050565b5f5f83116104d0576040517fe3c2448f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c08101825233815273ffffffffffffffffffffffffffffffffffffffff871660208201529081018590525f906060810161050f8642611eaa565b815260200185815260200184600281111561052c5761052c611bfd565b9052905061053981610cc5565b91506105458282610cf4565b8573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16837f5ba2bd70fc00e95083121c56c84817a196474482b43591f04856084f8aeb362f8888886040516105a793929190611ebd565b60405180910390a450949350505050565b5f8181526020819052604081205473ffffffffffffffffffffffffffffffffffffffff166105e757505f919050565b5f82815260208181526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416938101939093526002808201549284019290925260038101546060840152600481015460808401526005810154909160a084019160ff169081111561066657610666611bfd565b600281111561067757610677611bfd565b815250509050806040015181608001518260600151426106979190611eaa565b6106a19190611ed8565b6106ab9190611f10565b9392505050565b5f83815260208181526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416938101939093526002808201549284019290925260038101546060840152600481015460808401526005810154909160a084019160ff169081111561073157610731611bfd565b600281111561074257610742611bfd565b905250805190915073ffffffffffffffffffffffffffffffffffffffff16610795576040517ee6a17000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f81608001518260600151426107ab9190611eaa565b6107b59190611ed8565b905060018110156107f2576040517fc850188000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61082c8260400151826108059190611f10565b7f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e9090610e56565b608082015161083b9082611f10565b8260600181815161084c9190611f27565b9052505f85815260208181526040918290208451815473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161783559286015160018084018054929093169190941617905591840151600280840191909155606085015160038401556080850151600484015560a0850151600584018054879594929391927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911691849081111561092057610920611bfd565b0217905550600291506109309050565b8260a00151600281111561094657610946611bfd565b0361095a576109558583610e5d565b610a03565b5f8260a00151600281111561097157610971611bfd565b036109aa575f80808080610987888a018a612299565b945094509450945094506109a08a888787878787611102565b5050505050610a03565b60018260a0015160028111156109c2576109c2611bfd565b036109d1576109558583611470565b6040517fd67592f600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050505050565b610a143382610ad0565b50565b6318fb58646004525f81815260249020801954604051919068fbb67fda52d4bfb8bf906020840181610a905783548015610a8a57808414150281526001848101549092508015610a8a57808414150260208201526002848101549092508015610a8a576003925083811415810260408301525b50610abb565b8160011c91505f5b82811015610ab957848101548481141502600582901b830152600101610a98565b505b8185528160051b810160405250505050919050565b5f81815260208181526040808320815160c081018352815473ffffffffffffffffffffffffffffffffffffffff9081168252600183015416938101939093526002808201549284019290925260038101546060840152600481015460808401526005810154909160a084019160ff1690811115610b4f57610b4f611bfd565b6002811115610b6057610b60611bfd565b8152505090508273ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff1614610bce576040517f2e9cd3ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f8281526020818152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000908116825560018083018054909216909155600282018590556003820185905560048201859055600590910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055845173ffffffffffffffffffffffffffffffffffffffff1684529091529020610c7a90836116a7565b50805160405173ffffffffffffffffffffffffffffffffffffffff9091169083907f59332f9abbff096727b5f98534b0146dcab05c8a32ebce917a9fa6c66e7033a1905f90a3505050565b5f81604051602001610cd79190611c3e565b604051602081830303815290604052805190602001209050919050565b5f8281526020819052604090205473ffffffffffffffffffffffffffffffffffffffff1615610d4f576040517f066e20da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f82815260208181526040918290208351815473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161783559285015160018084018054929093169190941617905591830151600280840191909155606084015160038401556080840151600484015560a0840151600584018054869594929391927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909116918490811115610e2057610e20611bfd565b021790555050815173ffffffffffffffffffffffffffffffffffffffff165f9081526001602052604090206103bb9150836117ae565b80825d5050565b6040805160018082528183019092525f9160208083019080368337019050509050815f0151815f81518110610e9457610e94611e50565b73ffffffffffffffffffffffffffffffffffffffff92909216602092830291909101909101526040805160018082528183019092525f918160200160208202803683370190505090508260400151815f81518110610ef457610ef4611e50565b602002602001018181525050825f015173ffffffffffffffffffffffffffffffffffffffff1663468721a773c12c1e50abb450d6205ea2c3fa861b3b834d13e85f86602001518686604051602401610f4e93929190612407565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f6cb498e500000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b168152610fe1939291905f90600401612487565b6020604051808303815f875af1158015610ffd573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061102191906124dc565b611057576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015173ffffffffffffffffffffffffffffffffffffffff16835f015173ffffffffffffffffffffffffffffffffffffffff16857fbdbaf70d5ad57b002382ab2439f43339eb5034dcb891ec13621a3009033f3e61866080015187606001516110c29190611f27565b60405190815260200160405180910390a46110fc7f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e906118c9565b50505050565b855f015173ffffffffffffffffffffffffffffffffffffffff1685828151811061112e5761112e611e50565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614611183576040517f891d7c4c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61118d83826118cf565b6111c3576040517fbb5c88e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60208601516111d5908490878561191d565b61120b576040517f9c8d2cd200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e905c61123685611a25565b1461126d576040517f2c5211c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b855f015173ffffffffffffffffffffffffffffffffffffffff1663468721a773c12c1e50abb450d6205ea2c3fa861b3b834d13e85f888888886040516024016112b994939291906125bd565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0d22d9b500000000000000000000000000000000000000000000000000000000179052517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815261134c939291905f90600401612487565b6020604051808303815f875af1158015611368573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061138c91906124dc565b6113c2576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b856020015173ffffffffffffffffffffffffffffffffffffffff16865f015173ffffffffffffffffffffffffffffffffffffffff16887fbdbaf70d5ad57b002382ab2439f43339eb5034dcb891ec13621a3009033f3e6189608001518a6060015161142d9190611f27565b60405190815260200160405180910390a46114677f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e906118c9565b50505050505050565b80516020808301516040805173ffffffffffffffffffffffffffffffffffffffff94851660248201819052949092166044830152606482018490527f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e905c608483015260a060a48301525f60c48084018290528251808503909101815260e4909301825292820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ff242432a00000000000000000000000000000000000000000000000000000000179052517f468721a700000000000000000000000000000000000000000000000000000000815263468721a7926115889273c12c1e50abb450d6205ea2c3fa861b3b834d13e8928290600401612487565b6020604051808303815f875af11580156115a4573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115c891906124dc565b6115fe576040517facfdb44400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806020015173ffffffffffffffffffffffffffffffffffffffff16815f015173ffffffffffffffffffffffffffffffffffffffff16837fbdbaf70d5ad57b002382ab2439f43339eb5034dcb891ec13621a3009033f3e61846080015185606001516116699190611f27565b60405190815260200160405180910390a46116a37f70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e906118c9565b5050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf83036116d45763f5a267f15f526004601cfd5b826116e65768fbb67fda52d4bfb8bf92505b8019548061174f5760019250838254036117135760018201805483556002830180549091555f90556117a6565b836001830154036117315760028201805460018401555f90556117a6565b83600283015403611747575f60028301556117a6565b5f92506117a6565b81602052835f5260405f208054806117685750506117a6565b60018360011c03925082600182031461179257828401548060018303860155805f52508060405f20555b5060018260011b178319555f815550600192505b505092915050565b6318fb58646004525f8281526024812068fbb67fda52d4bfb8bf83036117db5763f5a267f15f526004601cfd5b826117ed5768fbb67fda52d4bfb8bf92505b80195481602052806118915781548061180d5784835560019350506117a6565b84810361181a57506117a6565b600183015480611835578560018501556001945050506117a6565b8581036118435750506117a6565b60028401548061185f57866002860155600195505050506117a6565b86810361186e575050506117a6565b5f9283526040808420600190559183528183206002905582529020600390555060075b835f5260405f2080546118c057600191821c8381018690558083019182905590821b82178319559092506117a6565b50505092915050565b5f815d50565b5f5f5b835181101561191357828482815181106118ee576118ee611e50565b60200260200101515f015161ffff161461190b575f9150506102ae565b6001016118d2565b5060019392505050565b5f5f856001875161192e9190611eaa565b8151811061193e5761193e611e50565b602002602001015190505f81602001515190505f5f90505b81811015611a15575f8360200151828151811061197557611975611e50565b602002602001015160066119899190612667565b611994906004612684565b61ffff1690505f6119b087836119ab816002611f27565b611aad565b90508873ffffffffffffffffffffffffffffffffffffffff168882815181106119db576119db611e50565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1614611a0b575f95505050505050611a1d565b5050600101611956565b506001925050505b949350505050565b5f805b8251811015611aa757828181518110611a4357611a43611e50565b60200260200101515f015161ffff16600103611a9f57828181518110611a6b57611a6b611e50565b60200260200101516020015177ffffffffffffffffffffffffffffffffffffffffffffffff1682611a9c9190611f27565b91505b600101611a28565b50919050565b5f80611aba858585611afe565b90505f5b8151811015611af557818181518110611ad957611ad9611e50565b60209101015160f81c60089390931b9290921791600101611abe565b50509392505050565b60608351828111611b0d578092505b838111611b18578093505b50818310156106ab5750604051828203848401601f19601f830181165b8281015185820152810180611b35575050508060208301015f81526020810160405250808252509392505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611b86575f5ffd5b919050565b5f60208284031215611b9b575f5ffd5b6106ab82611b63565b602080825282518282018190525f918401906040840190835b81811015611bdb578351835260209384019390920191600101611bbd565b509095945050505050565b5f60208284031215611bf6575f5ffd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60038110611c3a57611c3a611bfd565b9052565b5f60c08201905073ffffffffffffffffffffffffffffffffffffffff835116825273ffffffffffffffffffffffffffffffffffffffff602084015116602083015260408301516040830152606083015160608301526080830151608083015260a0830151611caf60a0840182611c2a565b5092915050565b5f5f60208385031215611cc7575f5ffd5b823567ffffffffffffffff811115611cdd575f5ffd5b8301601f81018513611ced575f5ffd5b803567ffffffffffffffff811115611d03575f5ffd5b8560208260051b8401011115611d17575f5ffd5b6020919091019590945092505050565b5f5f60408385031215611d38575f5ffd5b82359150611d4860208401611b63565b90509250929050565b5f5f5f5f60808587031215611d64575f5ffd5b611d6d85611b63565b93506020850135925060408501359150606085013560038110611d8e575f5ffd5b939692955090935050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b602081525f6106ab6020830184611d99565b5f5f5f60408486031215611deb575f5ffd5b83359250602084013567ffffffffffffffff811115611e08575f5ffd5b8401601f81018613611e18575f5ffd5b803567ffffffffffffffff811115611e2e575f5ffd5b866020828401011115611e3f575f5ffd5b939660209190910195509293505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b818103818111156102ae576102ae611e7d565b8381526020810183905260608101611a1d6040830184611c2a565b5f82611f0b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b80820281158282048414176102ae576102ae611e7d565b808201808211156102ae576102ae611e7d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff81118282101715611f8a57611f8a611f3a565b60405290565b6040516060810167ffffffffffffffff81118282101715611f8a57611f8a611f3a565b604051601f8201601f1916810167ffffffffffffffff81118282101715611fdc57611fdc611f3a565b604052919050565b5f67ffffffffffffffff821115611ffd57611ffd611f3a565b5060051b60200190565b803561ffff81168114611b86575f5ffd5b5f82601f830112612027575f5ffd5b813561203a61203582611fe4565b611fb3565b8082825260208201915060208360061b86010192508583111561205b575f5ffd5b602085015b838110156120cd5760408188031215612077575f5ffd5b61207f611f67565b61208882612007565b8152602082013577ffffffffffffffffffffffffffffffffffffffffffffffff811681146120b4575f5ffd5b6020828101919091529084529290920191604001612060565b5095945050505050565b5f82601f8301126120e6575f5ffd5b813567ffffffffffffffff81111561210057612100611f3a565b6121136020601f19601f84011601611fb3565b818152846020838601011115612127575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f82601f830112612152575f5ffd5b813561216061203582611fe4565b8082825260208201915060208360051b860101925085831115612181575f5ffd5b602085015b838110156120cd57803567ffffffffffffffff8111156121a4575f5ffd5b86016060818903601f190112156121b9575f5ffd5b6121c1611f90565b6121cd60208301612007565b8152604082013567ffffffffffffffff8111156121e8575f5ffd5b82016020810190603f018a136121fc575f5ffd5b803561220a61203582611fe4565b8082825260208201915060208360051b85010192508c83111561222b575f5ffd5b6020840193505b828410156122545761224384612007565b825260209384019390910190612232565b6020850152505050606082013567ffffffffffffffff811115612275575f5ffd5b6122848a6020838601016120d7565b60408301525084525060209283019201612186565b5f5f5f5f5f60a086880312156122ad575f5ffd5b853567ffffffffffffffff8111156122c3575f5ffd5b8601601f810188136122d3575f5ffd5b80356122e161203582611fe4565b8082825260208201915060208360051b85010192508a831115612302575f5ffd5b6020840193505b8284101561232b5761231a84611b63565b825260209384019390910190612309565b9750505050602086013567ffffffffffffffff811115612349575f5ffd5b61235588828901612018565b945050604086013567ffffffffffffffff811115612371575f5ffd5b61237d88828901612143565b935050606086013567ffffffffffffffff811115612399575f5ffd5b6123a5888289016120d7565b95989497509295608001359392505050565b5f8151808452602084019350602083015f5b828110156123fd57815173ffffffffffffffffffffffffffffffffffffffff168652602095860195909101906001016123c9565b5093949350505050565b73ffffffffffffffffffffffffffffffffffffffff84168152608060208201525f61243560808301856123b7565b8281036040840152835180825260208086019201905f5b8181101561246a57835183526020938401939092019160010161244c565b505083810360608501525f81526020810192505050949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152608060408201525f6124bb6080830185611d99565b9050600283106124cd576124cd611bfd565b82606083015295945050505050565b5f602082840312156124ec575f5ffd5b815180151581146106ab575f5ffd5b5f82825180855260208501945060208160051b830101602085015f5b838110156125b157848303601f190188528151805161ffff168452602080820151606082870181905281519087018190529101905f9060808701905b8083101561257a5761ffff8451168252602082019150602084019350600183019250612553565b506040840151935086810360408801526125948185611d99565b965050505050602082019150602088019750600181019050612517565b50909695505050505050565b608081525f6125cf60808301876123b7565b82810360208401528086518083526020830191506020880192505f5b81811015612633578351805161ffff16845260209081015177ffffffffffffffffffffffffffffffffffffffffffffffff1681850152909301926040909201916001016125eb565b5050838103604085015261264781876124fb565b915050828103606084015261265c8185611d99565b979650505050505050565b61ffff8181168382160290811690818114611caf57611caf611e7d565b61ffff81811683821601908111156102ae576102ae611e7d56fea2646970667358221220b31c6eb74716542e5eee381275d609f5778bf96b7fe95b8ae16673e7038a214464736f6c634300081c0033", + "nonce": "0xa", + "chainId": "0x64" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x27da87", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xc6f3afbd71041b5462e98a3fe2d7f10673afaee4a46aedec8d1ca4a14c1eeba5", + "transactionIndex": "0x5", + "blockHash": "0xf85394133cc2433fc93aadc3f0fe01d507478b5fab4a846c4a26e33914c49502", + "blockNumber": "0x273e210", + "gasUsed": "0x21769b", + "effectiveGasPrice": "0x295", + "from": "0xff1725e448313743f3062fa963449ebae46dda18", + "to": null, + "contractAddress": "0x7f15133efc558a93173cd182818cdd6b44c84a74" + } + ], + "libraries": [], + "pending": [], + "returns": { + "module": { + "internal_type": "contract SubscriptionModule", + "value": "0x7f15133efC558a93173cD182818cdd6b44C84a74" + } + }, + "timestamp": 1752838978, + "chain": 100, + "commit": "1908d19" +} \ No newline at end of file diff --git a/script/SubscriptionModule.flattened.sol b/script/SubscriptionModule.flattened.sol new file mode 100644 index 0000000..af3232f --- /dev/null +++ b/script/SubscriptionModule.flattened.sol @@ -0,0 +1,8263 @@ +// SPDX-License-Identifier: MIT +pragma solidity <0.9.0 >=0.7.0 >=0.8.24 ^0.8.0 ^0.8.20 ^0.8.28 ^0.8.4; + +// lib/circles-contracts-v2/lib/abdk-libraries-solidity/ABDKMath64x64.sol + +/* + * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. + * Author: Mikhail Vladimirov + */ + +/** + * Smart contract library of mathematical functions operating with signed + * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is + * basically a simple fraction whose numerator is signed 128-bit integer and + * denominator is 2^64. As long as denominator is always the same, there is no + * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are + * represented by int128 type holding only the numerator. + */ +library ABDKMath64x64 { + /* + * Minimum value signed 64.64-bit fixed point number may have. + */ + int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; + + /* + * Maximum value signed 64.64-bit fixed point number may have. + */ + int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + /** + * Convert signed 256-bit integer number into signed 64.64-bit fixed point + * number. Revert on overflow. + * + * @param x signed 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function fromInt(int256 x) internal pure returns (int128) { + unchecked { + require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF); + return int128(x << 64); + } + } + + /** + * Convert signed 64.64 fixed point number into signed 64-bit integer number + * rounding down. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64-bit integer number + */ + function toInt(int128 x) internal pure returns (int64) { + unchecked { + return int64(x >> 64); + } + } + + /** + * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point + * number. Revert on overflow. + * + * @param x unsigned 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function fromUInt(uint256 x) internal pure returns (int128) { + unchecked { + require(x <= 0x7FFFFFFFFFFFFFFF); + return int128(int256(x << 64)); + } + } + + /** + * Convert signed 64.64 fixed point number into unsigned 64-bit integer + * number rounding down. Revert on underflow. + * + * @param x signed 64.64-bit fixed point number + * @return unsigned 64-bit integer number + */ + function toUInt(int128 x) internal pure returns (uint64) { + unchecked { + require(x >= 0); + return uint64(uint128(x >> 64)); + } + } + + /** + * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point + * number rounding down. Revert on overflow. + * + * @param x signed 128.128-bin fixed point number + * @return signed 64.64-bit fixed point number + */ + function from128x128(int256 x) internal pure returns (int128) { + unchecked { + int256 result = x >> 64; + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Convert signed 64.64 fixed point number into signed 128.128 fixed point + * number. + * + * @param x signed 64.64-bit fixed point number + * @return signed 128.128 fixed point number + */ + function to128x128(int128 x) internal pure returns (int256) { + unchecked { + return int256(x) << 64; + } + } + + /** + * Calculate x + y. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function add(int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 result = int256(x) + y; + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Calculate x - y. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function sub(int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 result = int256(x) - y; + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Calculate x * y rounding down. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function mul(int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 result = int256(x) * y >> 64; + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point + * number and y is signed 256-bit integer number. Revert on overflow. + * + * @param x signed 64.64 fixed point number + * @param y signed 256-bit integer number + * @return signed 256-bit integer number + */ + function muli(int128 x, int256 y) internal pure returns (int256) { + unchecked { + if (x == MIN_64x64) { + require( + y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF + && y <= 0x1000000000000000000000000000000000000000000000000 + ); + return -y << 63; + } else { + bool negativeResult = false; + if (x < 0) { + x = -x; + negativeResult = true; + } + if (y < 0) { + y = -y; // We rely on overflow behavior here + negativeResult = !negativeResult; + } + uint256 absoluteResult = mulu(x, uint256(y)); + if (negativeResult) { + require(absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000); + return -int256(absoluteResult); // We rely on overflow behavior here + } else { + require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int256(absoluteResult); + } + } + } + } + + /** + * Calculate x * y rounding down, where x is signed 64.64 fixed point number + * and y is unsigned 256-bit integer number. Revert on overflow. + * + * @param x signed 64.64 fixed point number + * @param y unsigned 256-bit integer number + * @return unsigned 256-bit integer number + */ + function mulu(int128 x, uint256 y) internal pure returns (uint256) { + unchecked { + if (y == 0) return 0; + + require(x >= 0); + + uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; + uint256 hi = uint256(int256(x)) * (y >> 128); + + require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + hi <<= 64; + + require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo); + return hi + lo; + } + } + + /** + * Calculate x / y rounding towards zero. Revert on overflow or when y is + * zero. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function div(int128 x, int128 y) internal pure returns (int128) { + unchecked { + require(y != 0); + int256 result = (int256(x) << 64) / y; + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Calculate x / y rounding towards zero, where x and y are signed 256-bit + * integer numbers. Revert on overflow or when y is zero. + * + * @param x signed 256-bit integer number + * @param y signed 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function divi(int256 x, int256 y) internal pure returns (int128) { + unchecked { + require(y != 0); + + bool negativeResult = false; + if (x < 0) { + x = -x; // We rely on overflow behavior here + negativeResult = true; + } + if (y < 0) { + y = -y; // We rely on overflow behavior here + negativeResult = !negativeResult; + } + uint128 absoluteResult = divuu(uint256(x), uint256(y)); + if (negativeResult) { + require(absoluteResult <= 0x80000000000000000000000000000000); + return -int128(absoluteResult); // We rely on overflow behavior here + } else { + require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int128(absoluteResult); // We rely on overflow behavior here + } + } + } + + /** + * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit + * integer numbers. Revert on overflow or when y is zero. + * + * @param x unsigned 256-bit integer number + * @param y unsigned 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function divu(uint256 x, uint256 y) internal pure returns (int128) { + unchecked { + require(y != 0); + uint128 result = divuu(x, y); + require(result <= uint128(MAX_64x64)); + return int128(result); + } + } + + /** + * Calculate -x. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function neg(int128 x) internal pure returns (int128) { + unchecked { + require(x != MIN_64x64); + return -x; + } + } + + /** + * Calculate |x|. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function abs(int128 x) internal pure returns (int128) { + unchecked { + require(x != MIN_64x64); + return x < 0 ? -x : x; + } + } + + /** + * Calculate 1 / x rounding towards zero. Revert on overflow or when x is + * zero. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function inv(int128 x) internal pure returns (int128) { + unchecked { + require(x != 0); + int256 result = int256(0x100000000000000000000000000000000) / x; + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function avg(int128 x, int128 y) internal pure returns (int128) { + unchecked { + return int128((int256(x) + int256(y)) >> 1); + } + } + + /** + * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. + * Revert on overflow or in case x * y is negative. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function gavg(int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 m = int256(x) * int256(y); + require(m >= 0); + require(m < 0x4000000000000000000000000000000000000000000000000000000000000000); + return int128(sqrtu(uint256(m))); + } + } + + /** + * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number + * and y is unsigned 256-bit integer number. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y uint256 value + * @return signed 64.64-bit fixed point number + */ + function pow(int128 x, uint256 y) internal pure returns (int128) { + unchecked { + bool negative = x < 0 && y & 1 == 1; + + uint256 absX = uint128(x < 0 ? -x : x); + uint256 absResult; + absResult = 0x100000000000000000000000000000000; + + if (absX <= 0x10000000000000000) { + absX <<= 63; + while (y != 0) { + if (y & 0x1 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + if (y & 0x2 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + if (y & 0x4 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + if (y & 0x8 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + y >>= 4; + } + + absResult >>= 64; + } else { + uint256 absXShift = 63; + if (absX < 0x1000000000000000000000000) { + absX <<= 32; + absXShift -= 32; + } + if (absX < 0x10000000000000000000000000000) { + absX <<= 16; + absXShift -= 16; + } + if (absX < 0x1000000000000000000000000000000) { + absX <<= 8; + absXShift -= 8; + } + if (absX < 0x10000000000000000000000000000000) { + absX <<= 4; + absXShift -= 4; + } + if (absX < 0x40000000000000000000000000000000) { + absX <<= 2; + absXShift -= 2; + } + if (absX < 0x80000000000000000000000000000000) { + absX <<= 1; + absXShift -= 1; + } + + uint256 resultShift = 0; + while (y != 0) { + require(absXShift < 64); + + if (y & 0x1 != 0) { + absResult = absResult * absX >> 127; + resultShift += absXShift; + if (absResult > 0x100000000000000000000000000000000) { + absResult >>= 1; + resultShift += 1; + } + } + absX = absX * absX >> 127; + absXShift <<= 1; + if (absX >= 0x100000000000000000000000000000000) { + absX >>= 1; + absXShift += 1; + } + + y >>= 1; + } + + require(resultShift < 64); + absResult >>= 64 - resultShift; + } + int256 result = negative ? -int256(absResult) : int256(absResult); + require(result >= MIN_64x64 && result <= MAX_64x64); + return int128(result); + } + } + + /** + * Calculate sqrt (x) rounding down. Revert if x < 0. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function sqrt(int128 x) internal pure returns (int128) { + unchecked { + require(x >= 0); + return int128(sqrtu(uint256(int256(x)) << 64)); + } + } + + /** + * Calculate binary logarithm of x. Revert if x <= 0. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function log_2(int128 x) internal pure returns (int128) { + unchecked { + require(x > 0); + + int256 msb = 0; + int256 xc = x; + if (xc >= 0x10000000000000000) { + xc >>= 64; + msb += 64; + } + if (xc >= 0x100000000) { + xc >>= 32; + msb += 32; + } + if (xc >= 0x10000) { + xc >>= 16; + msb += 16; + } + if (xc >= 0x100) { + xc >>= 8; + msb += 8; + } + if (xc >= 0x10) { + xc >>= 4; + msb += 4; + } + if (xc >= 0x4) { + xc >>= 2; + msb += 2; + } + if (xc >= 0x2) msb += 1; // No need to shift xc anymore + + int256 result = msb - 64 << 64; + uint256 ux = uint256(int256(x)) << uint256(127 - msb); + for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { + ux *= ux; + uint256 b = ux >> 255; + ux >>= 127 + b; + result += bit * int256(b); + } + + return int128(result); + } + } + + /** + * Calculate natural logarithm of x. Revert if x <= 0. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function ln(int128 x) internal pure returns (int128) { + unchecked { + require(x > 0); + + return int128(int256(uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128)); + } + } + + /** + * Calculate binary exponent of x. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function exp_2(int128 x) internal pure returns (int128) { + unchecked { + require(x < 0x400000000000000000); // Overflow + + if (x < -0x400000000000000000) return 0; // Underflow + + uint256 result = 0x80000000000000000000000000000000; + + if (x & 0x8000000000000000 > 0) { + result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128; + } + if (x & 0x4000000000000000 > 0) { + result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128; + } + if (x & 0x2000000000000000 > 0) { + result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128; + } + if (x & 0x1000000000000000 > 0) { + result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128; + } + if (x & 0x800000000000000 > 0) { + result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128; + } + if (x & 0x400000000000000 > 0) { + result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128; + } + if (x & 0x200000000000000 > 0) { + result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128; + } + if (x & 0x100000000000000 > 0) { + result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128; + } + if (x & 0x80000000000000 > 0) { + result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128; + } + if (x & 0x40000000000000 > 0) { + result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128; + } + if (x & 0x20000000000000 > 0) { + result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128; + } + if (x & 0x10000000000000 > 0) { + result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128; + } + if (x & 0x8000000000000 > 0) { + result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128; + } + if (x & 0x4000000000000 > 0) { + result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128; + } + if (x & 0x2000000000000 > 0) { + result = result * 0x1000162E525EE054754457D5995292026 >> 128; + } + if (x & 0x1000000000000 > 0) { + result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128; + } + if (x & 0x800000000000 > 0) { + result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128; + } + if (x & 0x400000000000 > 0) { + result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128; + } + if (x & 0x200000000000 > 0) { + result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128; + } + if (x & 0x100000000000 > 0) { + result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128; + } + if (x & 0x80000000000 > 0) { + result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128; + } + if (x & 0x40000000000 > 0) { + result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128; + } + if (x & 0x20000000000 > 0) { + result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128; + } + if (x & 0x10000000000 > 0) { + result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128; + } + if (x & 0x8000000000 > 0) { + result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128; + } + if (x & 0x4000000000 > 0) { + result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128; + } + if (x & 0x2000000000 > 0) { + result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128; + } + if (x & 0x1000000000 > 0) { + result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128; + } + if (x & 0x800000000 > 0) { + result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128; + } + if (x & 0x400000000 > 0) { + result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128; + } + if (x & 0x200000000 > 0) { + result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128; + } + if (x & 0x100000000 > 0) { + result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128; + } + if (x & 0x80000000 > 0) { + result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128; + } + if (x & 0x40000000 > 0) { + result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128; + } + if (x & 0x20000000 > 0) { + result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128; + } + if (x & 0x10000000 > 0) { + result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128; + } + if (x & 0x8000000 > 0) { + result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128; + } + if (x & 0x4000000 > 0) { + result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128; + } + if (x & 0x2000000 > 0) { + result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128; + } + if (x & 0x1000000 > 0) { + result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128; + } + if (x & 0x800000 > 0) { + result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128; + } + if (x & 0x400000 > 0) { + result = result * 0x100000000002C5C85FDF477B662B26945 >> 128; + } + if (x & 0x200000 > 0) { + result = result * 0x10000000000162E42FEFA3AE53369388C >> 128; + } + if (x & 0x100000 > 0) { + result = result * 0x100000000000B17217F7D1D351A389D40 >> 128; + } + if (x & 0x80000 > 0) { + result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128; + } + if (x & 0x40000 > 0) { + result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128; + } + if (x & 0x20000 > 0) { + result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128; + } + if (x & 0x10000 > 0) { + result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128; + } + if (x & 0x8000 > 0) { + result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128; + } + if (x & 0x4000 > 0) { + result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128; + } + if (x & 0x2000 > 0) { + result = result * 0x1000000000000162E42FEFA39F02B772C >> 128; + } + if (x & 0x1000 > 0) { + result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128; + } + if (x & 0x800 > 0) { + result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128; + } + if (x & 0x400 > 0) { + result = result * 0x100000000000002C5C85FDF473DEA871F >> 128; + } + if (x & 0x200 > 0) { + result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128; + } + if (x & 0x100 > 0) { + result = result * 0x100000000000000B17217F7D1CF79E949 >> 128; + } + if (x & 0x80 > 0) { + result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128; + } + if (x & 0x40 > 0) { + result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128; + } + if (x & 0x20 > 0) { + result = result * 0x100000000000000162E42FEFA39EF366F >> 128; + } + if (x & 0x10 > 0) { + result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128; + } + if (x & 0x8 > 0) { + result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128; + } + if (x & 0x4 > 0) { + result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128; + } + if (x & 0x2 > 0) { + result = result * 0x1000000000000000162E42FEFA39EF358 >> 128; + } + if (x & 0x1 > 0) { + result = result * 0x10000000000000000B17217F7D1CF79AB >> 128; + } + + result >>= uint256(int256(63 - (x >> 64))); + require(result <= uint256(int256(MAX_64x64))); + + return int128(int256(result)); + } + } + + /** + * Calculate natural exponent of x. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function exp(int128 x) internal pure returns (int128) { + unchecked { + require(x < 0x400000000000000000); // Overflow + + if (x < -0x400000000000000000) return 0; // Underflow + + return exp_2(int128(int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128)); + } + } + + /** + * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit + * integer numbers. Revert on overflow or when y is zero. + * + * @param x unsigned 256-bit integer number + * @param y unsigned 256-bit integer number + * @return unsigned 64.64-bit fixed point number + */ + function divuu(uint256 x, uint256 y) private pure returns (uint128) { + unchecked { + require(y != 0); + + uint256 result; + + if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) { + result = (x << 64) / y; + } else { + uint256 msb = 192; + uint256 xc = x >> 192; + if (xc >= 0x100000000) { + xc >>= 32; + msb += 32; + } + if (xc >= 0x10000) { + xc >>= 16; + msb += 16; + } + if (xc >= 0x100) { + xc >>= 8; + msb += 8; + } + if (xc >= 0x10) { + xc >>= 4; + msb += 4; + } + if (xc >= 0x4) { + xc >>= 2; + msb += 2; + } + if (xc >= 0x2) msb += 1; // No need to shift xc anymore + + result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1); + require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + uint256 hi = result * (y >> 128); + uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + uint256 xh = x >> 192; + uint256 xl = x << 64; + + if (xl < lo) xh -= 1; + xl -= lo; // We rely on overflow behavior here + lo = hi << 128; + if (xl < lo) xh -= 1; + xl -= lo; // We rely on overflow behavior here + + result += xh == hi >> 128 ? xl / y : 1; + } + + require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return uint128(result); + } + } + + /** + * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer + * number. + * + * @param x unsigned 256-bit integer number + * @return unsigned 128-bit integer number + */ + function sqrtu(uint256 x) private pure returns (uint128) { + unchecked { + if (x == 0) { + return 0; + } else { + uint256 xx = x; + uint256 r = 1; + if (xx >= 0x100000000000000000000000000000000) { + xx >>= 128; + r <<= 64; + } + if (xx >= 0x10000000000000000) { + xx >>= 64; + r <<= 32; + } + if (xx >= 0x100000000) { + xx >>= 32; + r <<= 16; + } + if (xx >= 0x10000) { + xx >>= 16; + r <<= 8; + } + if (xx >= 0x100) { + xx >>= 8; + r <<= 4; + } + if (xx >= 0x10) { + xx >>= 4; + r <<= 2; + } + if (xx >= 0x4) r <<= 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; // Seven iterations should be enough + uint256 r1 = x / r; + return uint128(r < r1 ? r : r1); + } + } + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Comparators.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Comparators.sol) + +/** + * @dev Provides a set of functions to compare values. + * + * _Available since v5.1._ + */ +library Comparators { + function lt(uint256 a, uint256 b) internal pure returns (bool) { + return a < b; + } + + function gt(uint256 a, uint256 b) internal pure returns (bool) { + return a > b; + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Context.sol + +// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } + + function _contextSuffixLength() internal view virtual returns (uint256) { + return 0; + } +} + +// lib/safe-smart-account/contracts/common/Enum.sol + +/** + * @title Enum - Collection of enums used in Safe contracts. + * @author Richard Meissner - @rmeissner + */ +abstract contract Enum { + enum Operation { + Call, + DelegateCall + } +} + +// lib/solady/src/utils/EnumerableSetLib.sol + +/// @notice Library for managing enumerable sets in storage. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EnumerableSetLib.sol) +/// +/// @dev Note: +/// In many applications, the number of elements in an enumerable set is small. +/// This enumerable set implementation avoids storing the length and indices +/// for up to 3 elements. Once the length exceeds 3 for the first time, the length +/// and indices will be initialized. The amortized cost of adding elements is O(1). +/// +/// The AddressSet implementation packs the length with the 0th entry. +/// +/// All enumerable sets except Uint8Set use a pop and swap mechanism to remove elements. +/// This means that the iteration order of elements can change between element removals. +library EnumerableSetLib { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The index must be less than the length. + error IndexOutOfBounds(); + + /// @dev The value cannot be the zero sentinel. + error ValueIsZeroSentinel(); + + /// @dev Cannot accommodate a new unique value with the capacity. + error ExceedsCapacity(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev A sentinel value to denote the zero value in storage. + /// No elements can be equal to this value. + /// `uint72(bytes9(keccak256(bytes("_ZERO_SENTINEL"))))`. + uint256 private constant _ZERO_SENTINEL = 0xfbb67fda52d4bfb8bf; + + /// @dev The storage layout is given by: + /// ``` + /// mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED) + /// mstore(0x00, set.slot) + /// let rootSlot := keccak256(0x00, 0x24) + /// mstore(0x20, rootSlot) + /// mstore(0x00, shr(96, shl(96, value))) + /// let positionSlot := keccak256(0x00, 0x40) + /// let valueSlot := add(rootSlot, sload(positionSlot)) + /// let valueInStorage := shr(96, sload(valueSlot)) + /// let lazyLength := shr(160, shl(160, sload(rootSlot))) + /// ``` + uint256 private constant _ENUMERABLE_ADDRESS_SET_SLOT_SEED = 0x978aab92; + + /// @dev The storage layout is given by: + /// ``` + /// mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED) + /// mstore(0x00, set.slot) + /// let rootSlot := keccak256(0x00, 0x24) + /// mstore(0x20, rootSlot) + /// mstore(0x00, value) + /// let positionSlot := keccak256(0x00, 0x40) + /// let valueSlot := add(rootSlot, sload(positionSlot)) + /// let valueInStorage := sload(valueSlot) + /// let lazyLength := sload(not(rootSlot)) + /// ``` + uint256 private constant _ENUMERABLE_WORD_SET_SLOT_SEED = 0x18fb5864; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRUCTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev An enumerable address set in storage. + struct AddressSet { + uint256 _spacer; + } + + /// @dev An enumerable bytes32 set in storage. + struct Bytes32Set { + uint256 _spacer; + } + + /// @dev An enumerable uint256 set in storage. + struct Uint256Set { + uint256 _spacer; + } + + /// @dev An enumerable int256 set in storage. + struct Int256Set { + uint256 _spacer; + } + + /// @dev An enumerable uint8 set in storage. Useful for enums. + struct Uint8Set { + uint256 data; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* GETTERS / SETTERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the number of elements in the set. + function length(AddressSet storage set) internal view returns (uint256 result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + let rootPacked := sload(rootSlot) + let n := shr(160, shl(160, rootPacked)) + result := shr(1, n) + for { } iszero(or(iszero(shr(96, rootPacked)), n)) { } { + result := 1 + if iszero(sload(add(rootSlot, result))) { break } + result := 2 + if iszero(sload(add(rootSlot, result))) { break } + result := 3 + break + } + } + } + + /// @dev Returns the number of elements in the set. + function length(Bytes32Set storage set) internal view returns (uint256 result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + let n := sload(not(rootSlot)) + result := shr(1, n) + for { } iszero(n) { } { + result := 0 + if iszero(sload(add(rootSlot, result))) { break } + result := 1 + if iszero(sload(add(rootSlot, result))) { break } + result := 2 + if iszero(sload(add(rootSlot, result))) { break } + result := 3 + break + } + } + } + + /// @dev Returns the number of elements in the set. + function length(Uint256Set storage set) internal view returns (uint256 result) { + result = length(_toBytes32Set(set)); + } + + /// @dev Returns the number of elements in the set. + function length(Int256Set storage set) internal view returns (uint256 result) { + result = length(_toBytes32Set(set)); + } + + /// @dev Returns the number of elements in the set. + function length(Uint8Set storage set) internal view returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + for { let packed := sload(set.slot) } packed { result := add(1, result) } { + packed := xor(packed, and(packed, add(1, not(packed)))) + } + } + } + + /// @dev Returns whether `value` is in the set. + function contains(AddressSet storage set, address value) internal view returns (bool result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + value := shr(96, shl(96, value)) + if eq(value, _ZERO_SENTINEL) { + mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. + revert(0x1c, 0x04) + } + if iszero(value) { value := _ZERO_SENTINEL } + let rootPacked := sload(rootSlot) + for { } 1 { } { + if iszero(shr(160, shl(160, rootPacked))) { + result := 1 + if eq(shr(96, rootPacked), value) { break } + if eq(shr(96, sload(add(rootSlot, 1))), value) { break } + if eq(shr(96, sload(add(rootSlot, 2))), value) { break } + result := 0 + break + } + mstore(0x20, rootSlot) + mstore(0x00, value) + result := iszero(iszero(sload(keccak256(0x00, 0x40)))) + break + } + } + } + + /// @dev Returns whether `value` is in the set. + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + if eq(value, _ZERO_SENTINEL) { + mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. + revert(0x1c, 0x04) + } + if iszero(value) { value := _ZERO_SENTINEL } + for { } 1 { } { + if iszero(sload(not(rootSlot))) { + result := 1 + if eq(sload(rootSlot), value) { break } + if eq(sload(add(rootSlot, 1)), value) { break } + if eq(sload(add(rootSlot, 2)), value) { break } + result := 0 + break + } + mstore(0x20, rootSlot) + mstore(0x00, value) + result := iszero(iszero(sload(keccak256(0x00, 0x40)))) + break + } + } + } + + /// @dev Returns whether `value` is in the set. + function contains(Uint256Set storage set, uint256 value) internal view returns (bool result) { + result = contains(_toBytes32Set(set), bytes32(value)); + } + + /// @dev Returns whether `value` is in the set. + function contains(Int256Set storage set, int256 value) internal view returns (bool result) { + result = contains(_toBytes32Set(set), bytes32(uint256(value))); + } + + /// @dev Returns whether `value` is in the set. + function contains(Uint8Set storage set, uint8 value) internal view returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := and(1, shr(and(0xff, value), sload(set.slot))) + } + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + function add(AddressSet storage set, address value) internal returns (bool result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + value := shr(96, shl(96, value)) + if eq(value, _ZERO_SENTINEL) { + mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. + revert(0x1c, 0x04) + } + if iszero(value) { value := _ZERO_SENTINEL } + let rootPacked := sload(rootSlot) + for { let n := shr(160, shl(160, rootPacked)) } 1 { } { + mstore(0x20, rootSlot) + if iszero(n) { + let v0 := shr(96, rootPacked) + if iszero(v0) { + sstore(rootSlot, shl(96, value)) + result := 1 + break + } + if eq(v0, value) { break } + let v1 := shr(96, sload(add(rootSlot, 1))) + if iszero(v1) { + sstore(add(rootSlot, 1), shl(96, value)) + result := 1 + break + } + if eq(v1, value) { break } + let v2 := shr(96, sload(add(rootSlot, 2))) + if iszero(v2) { + sstore(add(rootSlot, 2), shl(96, value)) + result := 1 + break + } + if eq(v2, value) { break } + mstore(0x00, v0) + sstore(keccak256(0x00, 0x40), 1) + mstore(0x00, v1) + sstore(keccak256(0x00, 0x40), 2) + mstore(0x00, v2) + sstore(keccak256(0x00, 0x40), 3) + rootPacked := or(rootPacked, 7) + n := 7 + } + mstore(0x00, value) + let p := keccak256(0x00, 0x40) + if iszero(sload(p)) { + n := shr(1, n) + result := 1 + sstore(p, add(1, n)) + if iszero(n) { + sstore(rootSlot, or(3, shl(96, value))) + break + } + sstore(add(rootSlot, n), shl(96, value)) + sstore(rootSlot, add(2, rootPacked)) + break + } + break + } + } + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + function add(Bytes32Set storage set, bytes32 value) internal returns (bool result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + if eq(value, _ZERO_SENTINEL) { + mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. + revert(0x1c, 0x04) + } + if iszero(value) { value := _ZERO_SENTINEL } + for { let n := sload(not(rootSlot)) } 1 { } { + mstore(0x20, rootSlot) + if iszero(n) { + let v0 := sload(rootSlot) + if iszero(v0) { + sstore(rootSlot, value) + result := 1 + break + } + if eq(v0, value) { break } + let v1 := sload(add(rootSlot, 1)) + if iszero(v1) { + sstore(add(rootSlot, 1), value) + result := 1 + break + } + if eq(v1, value) { break } + let v2 := sload(add(rootSlot, 2)) + if iszero(v2) { + sstore(add(rootSlot, 2), value) + result := 1 + break + } + if eq(v2, value) { break } + mstore(0x00, v0) + sstore(keccak256(0x00, 0x40), 1) + mstore(0x00, v1) + sstore(keccak256(0x00, 0x40), 2) + mstore(0x00, v2) + sstore(keccak256(0x00, 0x40), 3) + n := 7 + } + mstore(0x00, value) + let p := keccak256(0x00, 0x40) + if iszero(sload(p)) { + n := shr(1, n) + sstore(add(rootSlot, n), value) + sstore(p, add(1, n)) + sstore(not(rootSlot), or(1, shl(1, add(1, n)))) + result := 1 + break + } + break + } + } + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + function add(Uint256Set storage set, uint256 value) internal returns (bool result) { + result = add(_toBytes32Set(set), bytes32(value)); + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + function add(Int256Set storage set, int256 value) internal returns (bool result) { + result = add(_toBytes32Set(set), bytes32(uint256(value))); + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + function add(Uint8Set storage set, uint8 value) internal returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(set.slot) + let mask := shl(and(0xff, value), 1) + sstore(set.slot, or(result, mask)) + result := iszero(and(result, mask)) + } + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. + function add(AddressSet storage set, address value, uint256 cap) internal returns (bool result) { + if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. + function add(Bytes32Set storage set, bytes32 value, uint256 cap) internal returns (bool result) { + if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. + function add(Uint256Set storage set, uint256 value, uint256 cap) internal returns (bool result) { + if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. + function add(Int256Set storage set, int256 value, uint256 cap) internal returns (bool result) { + if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); + } + + /// @dev Adds `value` to the set. Returns whether `value` was not in the set. + /// Reverts if the set grows bigger than the custom on-the-fly capacity `cap`. + function add(Uint8Set storage set, uint8 value, uint256 cap) internal returns (bool result) { + if (result = add(set, value)) if (length(set) > cap) revert ExceedsCapacity(); + } + + /// @dev Removes `value` from the set. Returns whether `value` was in the set. + function remove(AddressSet storage set, address value) internal returns (bool result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + value := shr(96, shl(96, value)) + if eq(value, _ZERO_SENTINEL) { + mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. + revert(0x1c, 0x04) + } + if iszero(value) { value := _ZERO_SENTINEL } + let rootPacked := sload(rootSlot) + for { let n := shr(160, shl(160, rootPacked)) } 1 { } { + if iszero(n) { + result := 1 + if eq(shr(96, rootPacked), value) { + sstore(rootSlot, sload(add(rootSlot, 1))) + sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) + sstore(add(rootSlot, 2), 0) + break + } + if eq(shr(96, sload(add(rootSlot, 1))), value) { + sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) + sstore(add(rootSlot, 2), 0) + break + } + if eq(shr(96, sload(add(rootSlot, 2))), value) { + sstore(add(rootSlot, 2), 0) + break + } + result := 0 + break + } + mstore(0x20, rootSlot) + mstore(0x00, value) + let p := keccak256(0x00, 0x40) + let position := sload(p) + if iszero(position) { break } + n := sub(shr(1, n), 1) + if iszero(eq(sub(position, 1), n)) { + let lastValue := shr(96, sload(add(rootSlot, n))) + sstore(add(rootSlot, sub(position, 1)), shl(96, lastValue)) + mstore(0x00, lastValue) + sstore(keccak256(0x00, 0x40), position) + } + sstore(rootSlot, or(shl(96, shr(96, sload(rootSlot))), or(shl(1, n), 1))) + sstore(p, 0) + result := 1 + break + } + } + } + + /// @dev Removes `value` from the set. Returns whether `value` was in the set. + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + if eq(value, _ZERO_SENTINEL) { + mstore(0x00, 0xf5a267f1) // `ValueIsZeroSentinel()`. + revert(0x1c, 0x04) + } + if iszero(value) { value := _ZERO_SENTINEL } + for { let n := sload(not(rootSlot)) } 1 { } { + if iszero(n) { + result := 1 + if eq(sload(rootSlot), value) { + sstore(rootSlot, sload(add(rootSlot, 1))) + sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) + sstore(add(rootSlot, 2), 0) + break + } + if eq(sload(add(rootSlot, 1)), value) { + sstore(add(rootSlot, 1), sload(add(rootSlot, 2))) + sstore(add(rootSlot, 2), 0) + break + } + if eq(sload(add(rootSlot, 2)), value) { + sstore(add(rootSlot, 2), 0) + break + } + result := 0 + break + } + mstore(0x20, rootSlot) + mstore(0x00, value) + let p := keccak256(0x00, 0x40) + let position := sload(p) + if iszero(position) { break } + n := sub(shr(1, n), 1) + if iszero(eq(sub(position, 1), n)) { + let lastValue := sload(add(rootSlot, n)) + sstore(add(rootSlot, sub(position, 1)), lastValue) + mstore(0x00, lastValue) + sstore(keccak256(0x00, 0x40), position) + } + sstore(not(rootSlot), or(shl(1, n), 1)) + sstore(p, 0) + result := 1 + break + } + } + } + + /// @dev Removes `value` from the set. Returns whether `value` was in the set. + function remove(Uint256Set storage set, uint256 value) internal returns (bool result) { + result = remove(_toBytes32Set(set), bytes32(value)); + } + + /// @dev Removes `value` from the set. Returns whether `value` was in the set. + function remove(Int256Set storage set, int256 value) internal returns (bool result) { + result = remove(_toBytes32Set(set), bytes32(uint256(value))); + } + + /// @dev Removes `value` from the set. Returns whether `value` was in the set. + function remove(Uint8Set storage set, uint8 value) internal returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := sload(set.slot) + let mask := shl(and(0xff, value), 1) + sstore(set.slot, and(result, not(mask))) + result := iszero(iszero(and(result, mask))) + } + } + + /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. + function update(AddressSet storage set, address value, bool isAdd, uint256 cap) internal returns (bool) { + return isAdd ? add(set, value, cap) : remove(set, value); + } + + /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. + function update(Bytes32Set storage set, bytes32 value, bool isAdd, uint256 cap) internal returns (bool) { + return isAdd ? add(set, value, cap) : remove(set, value); + } + + /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. + function update(Uint256Set storage set, uint256 value, bool isAdd, uint256 cap) internal returns (bool) { + return isAdd ? add(set, value, cap) : remove(set, value); + } + + /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. + function update(Int256Set storage set, int256 value, bool isAdd, uint256 cap) internal returns (bool) { + return isAdd ? add(set, value, cap) : remove(set, value); + } + + /// @dev Shorthand for `isAdd ? set.add(value, cap) : set.remove(value)`. + function update(Uint8Set storage set, uint8 value, bool isAdd, uint256 cap) internal returns (bool) { + return isAdd ? add(set, value, cap) : remove(set, value); + } + + /// @dev Returns all of the values in the set. + /// Note: This can consume more gas than the block gas limit for large sets. + function values(AddressSet storage set) internal view returns (address[] memory result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + let zs := _ZERO_SENTINEL + let rootPacked := sload(rootSlot) + let n := shr(160, shl(160, rootPacked)) + result := mload(0x40) + let o := add(0x20, result) + let v := shr(96, rootPacked) + mstore(o, mul(v, iszero(eq(v, zs)))) + for { } 1 { } { + if iszero(n) { + if v { + n := 1 + v := shr(96, sload(add(rootSlot, n))) + if v { + n := 2 + mstore(add(o, 0x20), mul(v, iszero(eq(v, zs)))) + v := shr(96, sload(add(rootSlot, n))) + if v { + n := 3 + mstore(add(o, 0x40), mul(v, iszero(eq(v, zs)))) + } + } + } + break + } + n := shr(1, n) + for { let i := 1 } lt(i, n) { i := add(i, 1) } { + v := shr(96, sload(add(rootSlot, i))) + mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs)))) + } + break + } + mstore(result, n) + mstore(0x40, add(o, shl(5, n))) + } + } + + /// @dev Returns all of the values in the set. + /// Note: This can consume more gas than the block gas limit for large sets. + function values(Bytes32Set storage set) internal view returns (bytes32[] memory result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + let zs := _ZERO_SENTINEL + let n := sload(not(rootSlot)) + result := mload(0x40) + let o := add(0x20, result) + for { } 1 { } { + if iszero(n) { + let v := sload(rootSlot) + if v { + n := 1 + mstore(o, mul(v, iszero(eq(v, zs)))) + v := sload(add(rootSlot, n)) + if v { + n := 2 + mstore(add(o, 0x20), mul(v, iszero(eq(v, zs)))) + v := sload(add(rootSlot, n)) + if v { + n := 3 + mstore(add(o, 0x40), mul(v, iszero(eq(v, zs)))) + } + } + } + break + } + n := shr(1, n) + for { let i := 0 } lt(i, n) { i := add(i, 1) } { + let v := sload(add(rootSlot, i)) + mstore(add(o, shl(5, i)), mul(v, iszero(eq(v, zs)))) + } + break + } + mstore(result, n) + mstore(0x40, add(o, shl(5, n))) + } + } + + /// @dev Returns all of the values in the set. + /// Note: This can consume more gas than the block gas limit for large sets. + function values(Uint256Set storage set) internal view returns (uint256[] memory result) { + result = _toUints(values(_toBytes32Set(set))); + } + + /// @dev Returns all of the values in the set. + /// Note: This can consume more gas than the block gas limit for large sets. + function values(Int256Set storage set) internal view returns (int256[] memory result) { + result = _toInts(values(_toBytes32Set(set))); + } + + /// @dev Returns all of the values in the set. + function values(Uint8Set storage set) internal view returns (uint8[] memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let ptr := add(result, 0x20) + let o := 0 + for { let packed := sload(set.slot) } packed { } { + if iszero(and(packed, 0xffff)) { + o := add(o, 16) + packed := shr(16, packed) + continue + } + mstore(ptr, o) + ptr := add(ptr, shl(5, and(packed, 1))) + o := add(o, 1) + packed := shr(1, packed) + } + mstore(result, shr(5, sub(ptr, add(result, 0x20)))) + mstore(0x40, ptr) + } + } + + /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. + function at(AddressSet storage set, uint256 i) internal view returns (address result) { + bytes32 rootSlot = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + result := shr(96, sload(add(rootSlot, i))) + result := mul(result, iszero(eq(result, _ZERO_SENTINEL))) + } + if (i >= length(set)) revert IndexOutOfBounds(); + } + + /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. + function at(Bytes32Set storage set, uint256 i) internal view returns (bytes32 result) { + result = _rootSlot(set); + /// @solidity memory-safe-assembly + assembly { + result := sload(add(result, i)) + result := mul(result, iszero(eq(result, _ZERO_SENTINEL))) + } + if (i >= length(set)) revert IndexOutOfBounds(); + } + + /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. + function at(Uint256Set storage set, uint256 i) internal view returns (uint256 result) { + result = uint256(at(_toBytes32Set(set), i)); + } + + /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. + function at(Int256Set storage set, uint256 i) internal view returns (int256 result) { + result = int256(uint256(at(_toBytes32Set(set), i))); + } + + /// @dev Returns the element at index `i` in the set. Reverts if `i` is out-of-bounds. + function at(Uint8Set storage set, uint256 i) internal view returns (uint8 result) { + /// @solidity memory-safe-assembly + assembly { + let packed := sload(set.slot) + for { } 1 { + mstore(0x00, 0x4e23d035) // `IndexOutOfBounds()`. + revert(0x1c, 0x04) + } { + if iszero(lt(i, 256)) { continue } + for { let j := 0 } iszero(eq(i, j)) { } { + packed := xor(packed, and(packed, add(1, not(packed)))) + j := add(j, 1) + } + if iszero(packed) { continue } + break + } + // Find first set subroutine, optimized for smaller bytecode size. + let x := and(packed, add(1, not(packed))) + let r := shl(7, iszero(iszero(shr(128, x)))) + r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + // For the lower 5 bits of the result, use a De Bruijn lookup. + // forgefmt: disable-next-item + result := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f), + 0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405)) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PRIVATE HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns the root slot. + function _rootSlot(AddressSet storage s) private pure returns (bytes32 r) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _ENUMERABLE_ADDRESS_SET_SLOT_SEED) + mstore(0x00, s.slot) + r := keccak256(0x00, 0x24) + } + } + + /// @dev Returns the root slot. + function _rootSlot(Bytes32Set storage s) private pure returns (bytes32 r) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _ENUMERABLE_WORD_SET_SLOT_SEED) + mstore(0x00, s.slot) + r := keccak256(0x00, 0x24) + } + } + + /// @dev Casts to a Bytes32Set. + function _toBytes32Set(Uint256Set storage s) private pure returns (Bytes32Set storage c) { + /// @solidity memory-safe-assembly + assembly { + c.slot := s.slot + } + } + + /// @dev Casts to a Bytes32Set. + function _toBytes32Set(Int256Set storage s) private pure returns (Bytes32Set storage c) { + /// @solidity memory-safe-assembly + assembly { + c.slot := s.slot + } + } + + /// @dev Casts to a uint256 array. + function _toUints(bytes32[] memory a) private pure returns (uint256[] memory c) { + /// @solidity memory-safe-assembly + assembly { + c := a + } + } + + /// @dev Casts to a int256 array. + function _toInts(bytes32[] memory a) private pure returns (int256[] memory c) { + /// @solidity memory-safe-assembly + assembly { + c := a + } + } +} + +// lib/circles-contracts-v2/src/errors/Errors.sol + +// Explainer on error codes: 3 leading bits for the error type, 5 bits for the error code. +// +------------+-------------------+-------------+ +// | Error Type | Hex Code Range | Occurances | +// +------------+-------------------+-------------+ +// | 0 | 0x00 to 0x1F | 32 | +// | 1 | 0x20 to 0x3F | 32 | +// | 2 | 0x40 to 0x5F | 32 | +// | 3 | 0x60 to 0x7F | 32 | +// | 4 | 0x80 to 0x9F | 32 | +// | 5 | 0xA0 to 0xBF | 32 | +// | 6 | 0xC0 to 0xDF | 32 | +// | 7 | 0xE0 to 0xFF | 32 | +// +------------+-------------------+-------------+ +// +// for convenience a reference table for the 32 occurances hex conversions; +// so you can "add" the error type easily +// +------------+------------+------------+------------+------------+------------+------------+------------+ +// | Occurrence | Hex Code | Occurrence | Hex Code | Occurrence | Hex Code | Occurrence | Hex Code | +// +------------+------------+------------+------------+------------+------------+------------+------------+ +// | 0 | 0x00 | 1 | 0x01 | 2 | 0x02 | 3 | 0x03 | +// | 4 | 0x04 | 5 | 0x05 | 6 | 0x06 | 7 | 0x07 | +// | 8 | 0x08 | 9 | 0x09 | 10 | 0x0A | 11 | 0x0B | +// | 12 | 0x0C | 13 | 0x0D | 14 | 0x0E | 15 | 0x0F | +// | 16 | 0x10 | 17 | 0x11 | 18 | 0x12 | 19 | 0x13 | +// | 20 | 0x14 | 21 | 0x15 | 22 | 0x16 | 23 | 0x17 | +// | 24 | 0x18 | 25 | 0x19 | 26 | 0x1A | 27 | 0x1B | +// | 28 | 0x1C | 29 | 0x1D | 30 | 0x1E | 31 | 0x1F | +// +------------+------------+------------+------------+------------+------------+------------+------------+ + +interface ICirclesCompactErrors { + /** + * @dev CirclesErrorNoArgs is a generic error that does not require any arguments. + * error type: + * 0: 0x00 -> 0x1F CirclesAddressCannotBeZero + * 1: 0x20 -> 0x3F CirclesArrayMustNotBeEmpty (no occurances anymore; freed up) + * 2: 0x40 -> 0x5F CirclesAmountMustNotBeZero + * 3: 0x60 -> 0x7F CirclesHubFlowVerticesMustBeSorted + * 4: 0x80 -> 0x9F CirclesLogicAssertion + * 5: 0xA0 -> 0xBF CirclesArraysLengthMismatch + */ + error CirclesErrorNoArgs(uint8); + + /** + * @dev CirclesErrorOneAddressArg is a generic error that requires one address argument. + * error type: + * 0: 0x00 -> 0x1F CirclesHubMustBeHuman(avatar) + * 1: 0x20 -> 0x3F CirclesAvatarMustBeRegistered(avatar) + * 2: 0x40 -> 0x5F CirclesHubGroupIsNotRegistered(group) + * 3: 0x60 -> 0x7F CirclesHubRegisterAvatarV1MustBeStoppedBeforeEndOfInvitationPeriod(avatar) + * 4: 0x80 -> 0x9F CirclesHubAvatarAlreadyRegistered(avatar) + * 5: 0xA0 -> 0xBF CirclesHubInvalidTrustReceiver(trustReceiver) + * 6: 0xC0 -> 0xDF CirclesERC1155MintBlocked(human, ~mintV1Status~) + * 7: 0xE0 -> 0xFF CirclesInvalidFunctionCaller(caller) + */ + error CirclesErrorOneAddressArg(address, uint8); + + /** + * @dev CirclesErrorAddressUintArgs is a generic error that provides an address and a uint256 as arguments. + * error type: + * 0: 0x00 -> 0x1F CirclesHubOperatorNotApprovedForSource(source, streamIndex) + * 1: 0x20 -> 0x3F CirclesHubFlowEdgeIsNotPermitted(receiver, circlesId) + * 2: 0x40 -> 0x5F CirclesHubGroupMintPolicyRejectedBurn(burner, toTokenId(group)) + * 3: 0x60 -> 0x7F CirclesHubGroupMintPolicyRejectedMint(minter, toTokenId) + * 4: 0x80 -> 0x9F CirclesDemurrageAmountExceedsMaxUint192(account, circlesId) + * 5: 0xA0 -> 0xBF CirclesDemurrageDayBeforeLastUpdatedDay(account, lastDayUpdated) + */ + error CirclesErrorAddressUintArgs(address, uint256, uint8); +} + +interface IHubErrors { + // CirclesErrorOneAddressArg 3 + // error CirclesHubRegisterAvatarV1MustBeStoppedBeforeEndOfInvitationPeriod(address avatar, uint8 code); + + // CirclesErrorOneAddressArg 4 + // error CirclesHubAvatarAlreadyRegistered(address avatar, uint8 code); + + // CirclesErrorOneAddressArg 0 + // error CirclesHubMustBeHuman(address avatar, uint8 code); + + // CirclesErrorOneAddressArg 2 + // error CirclesHubGroupIsNotRegistered(address group, uint8 code); + + // CirclesErrorOneAddressArg 5 + // error CirclesHubInvalidTrustReceiver(address trustReceiver, uint8 code); + + // CirclesErrorAddressUintArgs 3 + // error CirclesHubGroupMintPolicyRejectedMint( + // address minter, address group, uint256[] collateral, uint256[] amounts, bytes data, uint8 code + // ); + + // CirclesErrorAddressUintArgs 2 + // error CirclesHubGroupMintPolicyRejectedBurn(address burner, address group, uint256 amount, bytes data, uint8 + // code); + + // CirclesErrorAddressUintArgs 0 + // error CirclesHubOperatorNotApprovedForSource(address operator, address source, uint16 streamIndex, uint8 code); + + // CirclesErrorAddressUintArgs 1 + // error CirclesHubFlowEdgeIsNotPermitted(address receiver, uint256 circlesId, uint8 code); + + // CirclesErrorNoArgs 3 + // error CirclesHubFlowVerticesMustBeSorted(); + + error CirclesHubFlowEdgeStreamMismatch(uint256 flowEdgeId, uint256 streamId, uint8 code); + + error CirclesHubStreamMismatch(uint256 streamId); + + error CirclesHubNettedFlowMismatch(uint256 vertexPosition, int256 matrixNettedFlow, int256 streamNettedFlow); +} + +interface ICirclesDemurrageErrors { + // CirclesErrorOneAddressArg 6 + // error CirclesERC1155MintBlocked(address human, address mintV1Status); + + // CirclesErrorAddressUintArgs 4 + // error CirclesDemurrageAmountExceedsMaxUint192(address account, uint256 circlesId, uint256 amount, uint8 code); + + // CirclesErrorAddressUintArgs 5 + // error CirclesDemurrageDayBeforeLastUpdatedDay( + // address account, uint256 circlesId, uint64 day, uint64 lastUpdatedDay, uint8 code + // ); + + error CirclesERC1155CannotReceiveBatch(uint8 code); +} + +interface ICirclesErrors { + // CirclesErrorOneAddressArg 1 + // error CirclesAvatarMustBeRegistered(address avatar, uint8 code); + + // CirclesErrorNoArgs 0 + // error CirclesAddressCannotBeZero(uint8 code); + + // CirclesErrorOneAddressArg + // error CirclesInvalidFunctionCaller(address caller, address expectedCaller, uint8 code); + + error CirclesInvalidCirclesId(uint256 id, uint8 code); + + error CirclesInvalidParameter(uint256 parameter, uint8 code); + + error CirclesAmountOverflow(uint256 amount, uint8 code); + + // CirclesErrorNoArgs 5 + // error CirclesArraysLengthMismatch(uint256 lengthArray1, uint256 lengthArray2, uint8 code); + + // CirclesErrorNoArgs 1 + // error CirclesArrayMustNotBeEmpty(uint8 code); + + // CirclesErrorNoArgs 2 + // error CirclesAmountMustNotBeZero(uint8 code); + + error CirclesProxyAlreadyInitialized(); + + // CirclesErrorNoArgs 4 + // error CirclesLogicAssertion(uint8 code); + + error CirclesIdMustBeDerivedFromAddress(uint256 providedId, uint8 code); + + error CirclesReentrancyGuard(uint8 code); +} + +interface IStandardTreasuryErrors { + error CirclesStandardTreasuryGroupHasNoVault(address group); + + error CirclesStandardTreasuryRedemptionCollateralMismatch( + uint256 circlesId, uint256[] redemptionIds, uint256[] redemptionValues, uint256[] burnIds, uint256[] burnValues + ); + + error CirclesStandardTreasuryInvalidMetadataType(bytes32 metadataType, uint8 code); + + error CirclesStandardTreasuryInvalidMetadata(bytes metadata, uint8 code); +} + +interface INameRegistryErrors { + error CirclesNamesInvalidName(address avatar, string name, uint8 code); + + error CirclesNamesShortNameAlreadyAssigned(address avatar, uint72 shortName, uint8 code); + + error CirclesNamesShortNameWithNonceTaken(address avatar, uint256 nonce, uint72 shortName, address takenByAvatar); + + error CirclesNamesAvatarAlreadyHasCustomNameOrSymbol(address avatar, string nameOrSymbol, uint8 code); + + error CirclesNamesOrganizationHasNoSymbol(address organization, uint8 code); + + error CirclesNamesShortNameZero(address avatar, uint256 nonce); +} + +interface IMigrationErrors { + error CirclesMigrationAmountMustBeGreaterThanZero(); +} + +// src/libs/Errors.sol + +library Errors { + error ExecutionFailed(); + + error InvalidAmount(); + + error IdentifierExists(); + + error IdentifierNonexistent(); + + error InvalidCategory(); + + error InvalidFrequency(); + + error InvalidRecipient(); + + error InvalidSubscriber(); + + error InvalidStreamSource(); + + error NotRedeemable(); + + error SingleStreamOnly(); + + error TrustedPathOnly(); + + error OnlyRecipient(); + + error OnlySubscriber(); +} + +// lib/circles-contracts-v2/src/circles/IDemurrage.sol + +interface IDemurrage { + function inflationDayZero() external view returns (uint256); +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol) + +/** + * @dev Interface of the ERC-165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[ERC]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} + +// src/interfaces/IMultiSend.sol + +interface IMultiSend { + function multiSend(bytes memory transactions) external payable; +} + +// lib/solady/src/utils/LibBytes.sol + +/// @notice Library for byte related operations. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol) +library LibBytes { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRUCTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Goated bytes storage struct that totally MOGs, no cap, fr. + /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af. + /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. + struct BytesStorage { + bytes32 _spacer; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The constant returned when the `search` is not found in the bytes. + uint256 internal constant NOT_FOUND = type(uint256).max; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTE STORAGE OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Sets the value of the bytes storage `$` to `s`. + function set(BytesStorage storage $, bytes memory s) internal { + /// @solidity memory-safe-assembly + assembly { + let n := mload(s) + let packed := or(0xff, shl(8, n)) + for { let i := 0 } 1 { } { + if iszero(gt(n, 0xfe)) { + i := 0x1f + packed := or(n, shl(8, mload(add(s, i)))) + if iszero(gt(n, i)) { break } + } + let o := add(s, 0x20) + mstore(0x00, $.slot) + for { let p := keccak256(0x00, 0x20) } 1 { } { + sstore(add(p, shr(5, i)), mload(add(o, i))) + i := add(i, 0x20) + if iszero(lt(i, n)) { break } + } + break + } + sstore($.slot, packed) + } + } + + /// @dev Sets the value of the bytes storage `$` to `s`. + function setCalldata(BytesStorage storage $, bytes calldata s) internal { + /// @solidity memory-safe-assembly + assembly { + let packed := or(0xff, shl(8, s.length)) + for { let i := 0 } 1 { } { + if iszero(gt(s.length, 0xfe)) { + i := 0x1f + packed := or(s.length, shl(8, shr(8, calldataload(s.offset)))) + if iszero(gt(s.length, i)) { break } + } + mstore(0x00, $.slot) + for { let p := keccak256(0x00, 0x20) } 1 { } { + sstore(add(p, shr(5, i)), calldataload(add(s.offset, i))) + i := add(i, 0x20) + if iszero(lt(i, s.length)) { break } + } + break + } + sstore($.slot, packed) + } + } + + /// @dev Sets the value of the bytes storage `$` to the empty bytes. + function clear(BytesStorage storage $) internal { + delete $._spacer; + } + + /// @dev Returns whether the value stored is `$` is the empty bytes "". + function isEmpty(BytesStorage storage $) internal view returns (bool) { + return uint256($._spacer) & 0xff == uint256(0); + } + + /// @dev Returns the length of the value stored in `$`. + function length(BytesStorage storage $) internal view returns (uint256 result) { + result = uint256($._spacer); + /// @solidity memory-safe-assembly + assembly { + let n := and(0xff, result) + result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n)))) + } + } + + /// @dev Returns the value stored in `$`. + function get(BytesStorage storage $) internal view returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let o := add(result, 0x20) + let packed := sload($.slot) + let n := shr(8, packed) + for { let i := 0 } 1 { } { + if iszero(eq(or(packed, 0xff), packed)) { + mstore(o, packed) + n := and(0xff, packed) + i := 0x1f + if iszero(gt(n, i)) { break } + } + mstore(0x00, $.slot) + for { let p := keccak256(0x00, 0x20) } 1 { } { + mstore(add(o, i), sload(add(p, shr(5, i)))) + i := add(i, 0x20) + if iszero(lt(i, n)) { break } + } + break + } + mstore(result, n) // Store the length of the memory. + mstore(add(o, n), 0) // Zeroize the slot after the bytes. + mstore(0x40, add(add(o, n), 0x20)) // Allocate memory. + } + } + + /// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0. + function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) { + /// @solidity memory-safe-assembly + assembly { + for { let packed := sload($.slot) } 1 { } { + if iszero(eq(or(packed, 0xff), packed)) { + if iszero(gt(i, 0x1e)) { + result := byte(i, packed) + break + } + if iszero(gt(i, and(0xff, packed))) { + mstore(0x00, $.slot) + let j := sub(i, 0x1f) + result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j)))) + } + break + } + if iszero(gt(i, shr(8, packed))) { + mstore(0x00, $.slot) + result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i)))) + } + break + } + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTES OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. + function replace( + bytes memory subject, + bytes memory needle, + bytes memory replacement + ) + internal + pure + returns (bytes memory result) + { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let needleLen := mload(needle) + let replacementLen := mload(replacement) + let d := sub(result, subject) // Memory difference. + let i := add(subject, 0x20) // Subject bytes pointer. + mstore(0x00, add(i, mload(subject))) // End of subject. + if iszero(gt(needleLen, mload(subject))) { + let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1) + let h := 0 // The hash of `needle`. + if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } + let s := mload(add(needle, 0x20)) + for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 { } { + let t := mload(i) + // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. + if iszero(shr(m, xor(t, s))) { + if h { + if iszero(eq(keccak256(i, needleLen), h)) { + mstore(add(i, d), t) + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + // Copy the `replacement` one word at a time. + for { let j := 0 } 1 { } { + mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) + j := add(j, 0x20) + if iszero(lt(j, replacementLen)) { break } + } + d := sub(add(d, replacementLen), needleLen) + if needleLen { + i := add(i, needleLen) + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + mstore(add(i, d), t) + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + } + } + let end := mload(0x00) + let n := add(sub(d, add(result, 0x20)), end) + // Copy the rest of the bytes one word at a time. + for { } lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } + let o := add(i, d) + mstore(o, 0) // Zeroize the slot after the bytes. + mstore(0x40, add(o, 0x20)) // Allocate memory. + mstore(result, n) // Store the length. + } + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from left to right, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function indexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + result := not(0) // Initialize to `NOT_FOUND`. + for { let subjectLen := mload(subject) } 1 { } { + if iszero(mload(needle)) { + result := from + if iszero(gt(from, subjectLen)) { break } + result := subjectLen + break + } + let needleLen := mload(needle) + let subjectStart := add(subject, 0x20) + + subject := add(subjectStart, from) + let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) + let m := shl(3, sub(0x20, and(needleLen, 0x1f))) + let s := mload(add(needle, 0x20)) + + if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } + + if iszero(lt(needleLen, 0x20)) { + for { let h := keccak256(add(needle, 0x20), needleLen) } 1 { } { + if iszero(shr(m, xor(mload(subject), s))) { + if eq(keccak256(subject, needleLen), h) { + result := sub(subject, subjectStart) + break + } + } + subject := add(subject, 1) + if iszero(lt(subject, end)) { break } + } + break + } + for { } 1 { } { + if iszero(shr(m, xor(mload(subject), s))) { + result := sub(subject, subjectStart) + break + } + subject := add(subject, 1) + if iszero(lt(subject, end)) { break } + } + break + } + } + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from left to right. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { + return indexOf(subject, needle, 0); + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from right to left, starting from `from`. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function lastIndexOf( + bytes memory subject, + bytes memory needle, + uint256 from + ) + internal + pure + returns (uint256 result) + { + /// @solidity memory-safe-assembly + assembly { + for { } 1 { } { + result := not(0) // Initialize to `NOT_FOUND`. + let needleLen := mload(needle) + if gt(needleLen, mload(subject)) { break } + let w := result + + let fromMax := sub(mload(subject), needleLen) + if iszero(gt(fromMax, from)) { from := fromMax } + + let end := add(add(subject, 0x20), w) + subject := add(add(subject, 0x20), from) + if iszero(gt(subject, end)) { break } + // As this function is not too often used, + // we shall simply use keccak256 for smaller bytecode size. + for { let h := keccak256(add(needle, 0x20), needleLen) } 1 { } { + if eq(keccak256(subject, needleLen), h) { + result := sub(subject, add(end, 1)) + break + } + subject := add(subject, w) // `sub(subject, 1)`. + if iszero(gt(subject, end)) { break } + } + break + } + } + } + + /// @dev Returns the byte index of the first location of `needle` in `subject`, + /// needleing from right to left. + /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. + function lastIndexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { + return lastIndexOf(subject, needle, type(uint256).max); + } + + /// @dev Returns true if `needle` is found in `subject`, false otherwise. + function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) { + return indexOf(subject, needle) != NOT_FOUND; + } + + /// @dev Returns whether `subject` starts with `needle`. + function startsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + let n := mload(needle) + // Just using keccak256 directly is actually cheaper. + let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n)) + result := lt(gt(n, mload(subject)), t) + } + } + + /// @dev Returns whether `subject` ends with `needle`. + function endsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + let n := mload(needle) + let notInRange := gt(n, mload(subject)) + // `subject + 0x20 + max(subject.length - needle.length, 0)`. + let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n))) + // Just using keccak256 directly is actually cheaper. + result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange) + } + } + + /// @dev Returns `subject` repeated `times`. + function repeat(bytes memory subject, uint256 times) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + let l := mload(subject) // Subject length. + if iszero(or(iszero(times), iszero(l))) { + result := mload(0x40) + subject := add(subject, 0x20) + let o := add(result, 0x20) + for { } 1 { } { + // Copy the `subject` one word at a time. + for { let j := 0 } 1 { } { + mstore(add(o, j), mload(add(subject, j))) + j := add(j, 0x20) + if iszero(lt(j, l)) { break } + } + o := add(o, l) + times := sub(times, 1) + if iszero(times) { break } + } + mstore(o, 0) // Zeroize the slot after the bytes. + mstore(0x40, add(o, 0x20)) // Allocate memory. + mstore(result, sub(o, add(result, 0x20))) // Store the length. + } + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). + /// `start` and `end` are byte offsets. + function slice(bytes memory subject, uint256 start, uint256 end) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + let l := mload(subject) // Subject length. + if iszero(gt(l, end)) { end := l } + if iszero(gt(l, start)) { start := l } + if lt(start, end) { + result := mload(0x40) + let n := sub(end, start) + let i := add(subject, start) + let w := not(0x1f) + // Copy the `subject` one word at a time, backwards. + for { let j := and(add(n, 0x1f), w) } 1 { } { + mstore(add(result, j), mload(add(i, j))) + j := add(j, w) // `sub(j, 0x20)`. + if iszero(j) { break } + } + let o := add(add(result, 0x20), n) + mstore(o, 0) // Zeroize the slot after the bytes. + mstore(0x40, add(o, 0x20)) // Allocate memory. + mstore(result, n) // Store the length. + } + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. + /// `start` is a byte offset. + function slice(bytes memory subject, uint256 start) internal pure returns (bytes memory result) { + result = slice(subject, start, type(uint256).max); + } + + /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). + /// `start` and `end` are byte offsets. Faster than Solidity's native slicing. + function sliceCalldata( + bytes calldata subject, + uint256 start, + uint256 end + ) + internal + pure + returns (bytes calldata result) + { + /// @solidity memory-safe-assembly + assembly { + end := xor(end, mul(xor(end, subject.length), lt(subject.length, end))) + start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) + result.offset := add(subject.offset, start) + result.length := mul(lt(start, end), sub(end, start)) + } + } + + /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. + /// `start` is a byte offset. Faster than Solidity's native slicing. + function sliceCalldata(bytes calldata subject, uint256 start) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) + result.offset := add(subject.offset, start) + result.length := mul(lt(start, subject.length), sub(subject.length, start)) + } + } + + /// @dev Reduces the size of `subject` to `n`. + /// If `n` is greater than the size of `subject`, this will be a no-op. + function truncate(bytes memory subject, uint256 n) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := subject + mstore(mul(lt(n, mload(result)), result), n) + } + } + + /// @dev Returns a copy of `subject`, with the length reduced to `n`. + /// If `n` is greater than the size of `subject`, this will be a no-op. + function truncatedCalldata(bytes calldata subject, uint256 n) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + result.offset := subject.offset + result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n))) + } + } + + /// @dev Returns all the indices of `needle` in `subject`. + /// The indices are byte offsets. + function indicesOf(bytes memory subject, bytes memory needle) internal pure returns (uint256[] memory result) { + /// @solidity memory-safe-assembly + assembly { + let searchLen := mload(needle) + if iszero(gt(searchLen, mload(subject))) { + result := mload(0x40) + let i := add(subject, 0x20) + let o := add(result, 0x20) + let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) + let h := 0 // The hash of `needle`. + if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } + let s := mload(add(needle, 0x20)) + for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 { } { + let t := mload(i) + // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. + if iszero(shr(m, xor(t, s))) { + if h { + if iszero(eq(keccak256(i, searchLen), h)) { + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. + o := add(o, 0x20) + i := add(i, searchLen) // Advance `i` by `searchLen`. + if searchLen { + if iszero(lt(i, subjectSearchEnd)) { break } + continue + } + } + i := add(i, 1) + if iszero(lt(i, subjectSearchEnd)) { break } + } + mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. + // Allocate memory for result. + // We allocate one more word, so this array can be recycled for {split}. + mstore(0x40, add(o, 0x20)) + } + } + } + + /// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes. + function split(bytes memory subject, bytes memory delimiter) internal pure returns (bytes[] memory result) { + uint256[] memory indices = indicesOf(subject, delimiter); + /// @solidity memory-safe-assembly + assembly { + let w := not(0x1f) + let indexPtr := add(indices, 0x20) + let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) + mstore(add(indicesEnd, w), mload(subject)) + mstore(indices, add(mload(indices), 1)) + for { let prevIndex := 0 } 1 { } { + let index := mload(indexPtr) + mstore(indexPtr, 0x60) + if iszero(eq(index, prevIndex)) { + let element := mload(0x40) + let l := sub(index, prevIndex) + mstore(element, l) // Store the length of the element. + // Copy the `subject` one word at a time, backwards. + for { let o := and(add(l, 0x1f), w) } 1 { } { + mstore(add(element, o), mload(add(add(subject, prevIndex), o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes. + // Allocate memory for the length and the bytes, rounded up to a multiple of 32. + mstore(0x40, add(element, and(add(l, 0x3f), w))) + mstore(indexPtr, element) // Store the `element` into the array. + } + prevIndex := add(index, mload(delimiter)) + indexPtr := add(indexPtr, 0x20) + if iszero(lt(indexPtr, indicesEnd)) { break } + } + result := indices + if iszero(mload(delimiter)) { + result := add(indices, 0x20) + mstore(result, sub(mload(indices), 2)) + } + } + } + + /// @dev Returns a concatenated bytes of `a` and `b`. + /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer. + function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + let w := not(0x1f) + let aLen := mload(a) + // Copy `a` one word at a time, backwards. + for { let o := and(add(aLen, 0x20), w) } 1 { } { + mstore(add(result, o), mload(add(a, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + let bLen := mload(b) + let output := add(result, aLen) + // Copy `b` one word at a time, backwards. + for { let o := and(add(bLen, 0x20), w) } 1 { } { + mstore(add(output, o), mload(add(b, o))) + o := add(o, w) // `sub(o, 0x20)`. + if iszero(o) { break } + } + let totalLen := add(aLen, bLen) + let last := add(add(result, 0x20), totalLen) + mstore(last, 0) // Zeroize the slot after the bytes. + mstore(result, totalLen) // Store the length. + mstore(0x40, add(last, 0x20)) // Allocate memory. + } + } + + /// @dev Returns whether `a` equals `b`. + function eq(bytes memory a, bytes memory b) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) + } + } + + /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes. + function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + // These should be evaluated on compile time, as far as possible. + let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. + let x := not(or(m, or(b, add(m, and(b, m))))) + let r := shl(7, iszero(iszero(shr(128, x)))) + r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + // forgefmt: disable-next-item + result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), + xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) + } + } + + /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. + /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. + function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) { + /// @solidity memory-safe-assembly + assembly { + let aLen := mload(a) + let bLen := mload(b) + let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f)) + if n { + for { let i := 0x20 } 1 { } { + let x := mload(add(a, i)) + let y := mload(add(b, i)) + if iszero(or(xor(x, y), eq(i, n))) { + i := add(i, 0x20) + continue + } + result := sub(gt(x, y), lt(x, y)) + break + } + } + // forgefmt: disable-next-item + if iszero(result) { + let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201 + let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0))) + let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0))) + result := sub(gt(x, y), lt(x, y)) + if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) } + } + } + } + + /// @dev Directly returns `a` without copying. + function directReturn(bytes memory a) internal pure { + /// @solidity memory-safe-assembly + assembly { + // Assumes that the bytes does not start from the scratch space. + let retStart := sub(a, 0x20) + let retUnpaddedSize := add(mload(a), 0x40) + // Right pad with zeroes. Just in case the bytes is produced + // by a method that doesn't zero right pad. + mstore(add(retStart, retUnpaddedSize), 0) + mstore(retStart, 0x20) // Store the return offset. + // End the transaction, returning the bytes. + return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) + } + } + + /// @dev Directly returns `a` with minimal copying. + function directReturn(bytes[] memory a) internal pure { + /// @solidity memory-safe-assembly + assembly { + let n := mload(a) // `a.length`. + let o := add(a, 0x20) // Start of elements in `a`. + let u := a // Highest memory slot. + let w := not(0x1f) + for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { + let c := add(o, shl(5, i)) // Location of pointer to `a[i]`. + let s := mload(c) // `a[i]`. + let l := mload(s) // `a[i].length`. + let r := and(l, 0x1f) // `a[i].length % 32`. + let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`. + // If `s` comes before `o`, or `s` is not zero right padded. + if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) { + let m := mload(0x40) + mstore(m, l) // Copy `a[i].length`. + for { } 1 { } { + mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards. + z := add(z, w) // `sub(z, 0x20)`. + if iszero(z) { break } + } + let e := add(add(m, 0x20), l) + mstore(e, 0) // Zeroize the slot after the copied bytes. + mstore(0x40, add(e, 0x20)) // Allocate memory. + s := m + } + mstore(c, sub(s, o)) // Convert to calldata offset. + let t := add(l, add(s, 0x20)) + if iszero(lt(t, u)) { u := t } + } + let retStart := add(a, w) // Assumes `a` doesn't start from scratch space. + mstore(retStart, 0x20) // Store the return offset. + return(retStart, add(0x40, sub(u, retStart))) // End the transaction. + } + } + + /// @dev Returns the word at `offset`, without any bounds checks. + function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(add(add(a, 0x20), offset)) + } + } + + /// @dev Returns the word at `offset`, without any bounds checks. + function loadCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + result := calldataload(add(a.offset, offset)) + } + } + + /// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks. + function staticStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + let l := sub(a.length, 0x20) + result.offset := add(a.offset, offset) + result.length := sub(a.length, offset) + if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) } + } + } + + /// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks. + function dynamicStructInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + let l := sub(a.length, 0x20) + let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. + result.offset := add(a.offset, s) + result.length := sub(a.length, s) + if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) } + } + } + + /// @dev Returns bytes in calldata. Performs bounds checks. + function bytesInCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + let l := sub(a.length, 0x20) + let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`. + result.offset := add(add(a.offset, s), 0x20) + result.length := calldataload(add(a.offset, s)) + // forgefmt: disable-next-item + if or(shr(64, or(result.length, or(s, or(l, a.offset)))), + or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) } + } + } + + /// @dev Returns empty calldata bytes. For silencing the compiler. + function emptyCalldata() internal pure returns (bytes calldata result) { + /// @solidity memory-safe-assembly + assembly { + result.length := 0 + } + } +} + +// lib/solady/src/utils/LibTransient.sol + +/// @notice Library for transient storage operations. +/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibTransient.sol) +/// @author Modified from Transient Goodies by Philogy +/// (https://github.com/Philogy/transient-goodies/blob/main/src/TransientBytesLib.sol) +/// +/// @dev Note: The functions postfixed with `Compat` will only use transient storage on L1. +/// L2s are super cheap anyway. +/// For best safety, always clear the storage after use. +library LibTransient { + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STRUCTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Pointer struct to a `uint256` in transient storage. + struct TUint256 { + uint256 _spacer; + } + + /// @dev Pointer struct to a `int256` in transient storage. + struct TInt256 { + uint256 _spacer; + } + + /// @dev Pointer struct to a `bytes32` in transient storage. + struct TBytes32 { + uint256 _spacer; + } + + /// @dev Pointer struct to a `address` in transient storage. + struct TAddress { + uint256 _spacer; + } + + /// @dev Pointer struct to a `bool` in transient storage. + struct TBool { + uint256 _spacer; + } + + /// @dev Pointer struct to a `bytes` in transient storage. + struct TBytes { + uint256 _spacer; + } + + /// @dev Pointer struct to a stack pointer generator in transient storage. + /// This stack does not directly take in values. Instead, it generates pointers + /// that can be casted to any of the other transient storage pointer struct. + struct TStack { + uint256 _spacer; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CUSTOM ERRORS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The transient stack is empty. + error StackIsEmpty(); + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* CONSTANTS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev The storage slot seed for converting a transient slot to a storage slot. + /// `bytes4(keccak256("_LIB_TRANSIENT_COMPAT_SLOT_SEED"))`. + uint256 private constant _LIB_TRANSIENT_COMPAT_SLOT_SEED = 0x5a0b45f2; + + /// @dev Multiplier to stack base slot, so that in the case where two stacks + /// share consecutive base slots, their pointers will likely not overlap. A prime. + uint256 private constant _STACK_BASE_SALT = 0x9e076501211e1371b; + + /// @dev The canonical address of the transient registry. + /// See: https://gist.github.com/Vectorized/4ab665d7a234ef5aaaff2e5091ec261f + address internal constant REGISTRY = 0x000000000000297f64C7F8d9595e43257908F170; + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* UINT256 OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a `uint256` in transient storage. + function tUint256(bytes32 tSlot) internal pure returns (TUint256 storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a `uint256` in transient storage. + function tUint256(uint256 tSlot) internal pure returns (TUint256 storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the value at transient `ptr`. + function get(TUint256 storage ptr) internal view returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + result := tload(ptr.slot) + } + } + + /// @dev Returns the value at transient `ptr`. + function getCompat(TUint256 storage ptr) internal view returns (uint256 result) { + result = block.chainid == 1 ? get(ptr) : _compat(ptr)._spacer; + } + + /// @dev Sets the value at transient `ptr`. + function set(TUint256 storage ptr, uint256 value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, value) + } + } + + /// @dev Sets the value at transient `ptr`. + function setCompat(TUint256 storage ptr, uint256 value) internal { + if (block.chainid == 1) return set(ptr, value); + _compat(ptr)._spacer = value; + } + + /// @dev Clears the value at transient `ptr`. + function clear(TUint256 storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, 0) + } + } + + /// @dev Clears the value at transient `ptr`. + function clearCompat(TUint256 storage ptr) internal { + if (block.chainid == 1) return clear(ptr); + _compat(ptr)._spacer = 0; + } + + /// @dev Increments the value at transient `ptr` by 1. + function inc(TUint256 storage ptr) internal returns (uint256 newValue) { + set(ptr, newValue = get(ptr) + 1); + } + + /// @dev Increments the value at transient `ptr` by 1. + function incCompat(TUint256 storage ptr) internal returns (uint256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) + 1); + } + + /// @dev Increments the value at transient `ptr` by `delta`. + function inc(TUint256 storage ptr, uint256 delta) internal returns (uint256 newValue) { + set(ptr, newValue = get(ptr) + delta); + } + + /// @dev Increments the value at transient `ptr` by `delta`. + function incCompat(TUint256 storage ptr, uint256 delta) internal returns (uint256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) + delta); + } + + /// @dev Decrements the value at transient `ptr` by 1. + function dec(TUint256 storage ptr) internal returns (uint256 newValue) { + set(ptr, newValue = get(ptr) - 1); + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function decCompat(TUint256 storage ptr) internal returns (uint256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) - 1); + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function dec(TUint256 storage ptr, uint256 delta) internal returns (uint256 newValue) { + set(ptr, newValue = get(ptr) - delta); + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function decCompat(TUint256 storage ptr, uint256 delta) internal returns (uint256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) - delta); + } + + /// @dev Increments the value at transient `ptr` by `delta`. + function incSigned(TUint256 storage ptr, int256 delta) internal returns (uint256 newValue) { + /// @solidity memory-safe-assembly + assembly { + let currentValue := tload(ptr.slot) + newValue := add(currentValue, delta) + if iszero(eq(lt(newValue, currentValue), slt(delta, 0))) { + mstore(0x00, 0x4e487b71) // `Panic(uint256)`. + mstore(0x20, 0x11) // Underflow or overflow panic. + revert(0x1c, 0x24) + } + tstore(ptr.slot, newValue) + } + } + + /// @dev Increments the value at transient `ptr` by `delta`. + function incSignedCompat(TUint256 storage ptr, int256 delta) internal returns (uint256 newValue) { + if (block.chainid == 1) return incSigned(ptr, delta); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + let currentValue := sload(ptr.slot) + newValue := add(currentValue, delta) + if iszero(eq(lt(newValue, currentValue), slt(delta, 0))) { + mstore(0x00, 0x4e487b71) // `Panic(uint256)`. + mstore(0x20, 0x11) // Underflow or overflow panic. + revert(0x1c, 0x24) + } + sstore(ptr.slot, newValue) + } + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function decSigned(TUint256 storage ptr, int256 delta) internal returns (uint256 newValue) { + /// @solidity memory-safe-assembly + assembly { + let currentValue := tload(ptr.slot) + newValue := sub(currentValue, delta) + if iszero(eq(lt(newValue, currentValue), sgt(delta, 0))) { + mstore(0x00, 0x4e487b71) // `Panic(uint256)`. + mstore(0x20, 0x11) // Underflow or overflow panic. + revert(0x1c, 0x24) + } + tstore(ptr.slot, newValue) + } + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function decSignedCompat(TUint256 storage ptr, int256 delta) internal returns (uint256 newValue) { + if (block.chainid == 1) return decSigned(ptr, delta); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + let currentValue := sload(ptr.slot) + newValue := sub(currentValue, delta) + if iszero(eq(lt(newValue, currentValue), sgt(delta, 0))) { + mstore(0x00, 0x4e487b71) // `Panic(uint256)`. + mstore(0x20, 0x11) // Underflow or overflow panic. + revert(0x1c, 0x24) + } + sstore(ptr.slot, newValue) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* INT256 OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a `int256` in transient storage. + function tInt256(bytes32 tSlot) internal pure returns (TInt256 storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a `int256` in transient storage. + function tInt256(uint256 tSlot) internal pure returns (TInt256 storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the value at transient `ptr`. + function get(TInt256 storage ptr) internal view returns (int256 result) { + /// @solidity memory-safe-assembly + assembly { + result := tload(ptr.slot) + } + } + + /// @dev Returns the value at transient `ptr`. + function getCompat(TInt256 storage ptr) internal view returns (int256 result) { + result = block.chainid == 1 ? get(ptr) : int256(_compat(ptr)._spacer); + } + + /// @dev Sets the value at transient `ptr`. + function set(TInt256 storage ptr, int256 value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, value) + } + } + + /// @dev Sets the value at transient `ptr`. + function setCompat(TInt256 storage ptr, int256 value) internal { + if (block.chainid == 1) return set(ptr, value); + _compat(ptr)._spacer = uint256(value); + } + + /// @dev Clears the value at transient `ptr`. + function clear(TInt256 storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, 0) + } + } + + /// @dev Clears the value at transient `ptr`. + function clearCompat(TInt256 storage ptr) internal { + if (block.chainid == 1) return clear(ptr); + _compat(ptr)._spacer = 0; + } + + /// @dev Increments the value at transient `ptr` by 1. + function inc(TInt256 storage ptr) internal returns (int256 newValue) { + set(ptr, newValue = get(ptr) + 1); + } + + /// @dev Increments the value at transient `ptr` by 1. + function incCompat(TInt256 storage ptr) internal returns (int256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) + 1); + } + + /// @dev Increments the value at transient `ptr` by `delta`. + function inc(TInt256 storage ptr, int256 delta) internal returns (int256 newValue) { + set(ptr, newValue = get(ptr) + delta); + } + + /// @dev Increments the value at transient `ptr` by `delta`. + function incCompat(TInt256 storage ptr, int256 delta) internal returns (int256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) + delta); + } + + /// @dev Decrements the value at transient `ptr` by 1. + function dec(TInt256 storage ptr) internal returns (int256 newValue) { + set(ptr, newValue = get(ptr) - 1); + } + + /// @dev Decrements the value at transient `ptr` by 1. + function decCompat(TInt256 storage ptr) internal returns (int256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) - 1); + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function dec(TInt256 storage ptr, int256 delta) internal returns (int256 newValue) { + set(ptr, newValue = get(ptr) - delta); + } + + /// @dev Decrements the value at transient `ptr` by `delta`. + function decCompat(TInt256 storage ptr, int256 delta) internal returns (int256 newValue) { + setCompat(ptr, newValue = getCompat(ptr) - delta); + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTES32 OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a `bytes32` in transient storage. + function tBytes32(bytes32 tSlot) internal pure returns (TBytes32 storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a `bytes32` in transient storage. + function tBytes32(uint256 tSlot) internal pure returns (TBytes32 storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the value at transient `ptr`. + function get(TBytes32 storage ptr) internal view returns (bytes32 result) { + /// @solidity memory-safe-assembly + assembly { + result := tload(ptr.slot) + } + } + + /// @dev Returns the value at transient `ptr`. + function getCompat(TBytes32 storage ptr) internal view returns (bytes32 result) { + result = block.chainid == 1 ? get(ptr) : bytes32(_compat(ptr)._spacer); + } + + /// @dev Sets the value at transient `ptr`. + function set(TBytes32 storage ptr, bytes32 value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, value) + } + } + + /// @dev Sets the value at transient `ptr`. + function setCompat(TBytes32 storage ptr, bytes32 value) internal { + if (block.chainid == 1) return set(ptr, value); + _compat(ptr)._spacer = uint256(value); + } + + /// @dev Clears the value at transient `ptr`. + function clear(TBytes32 storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, 0) + } + } + + /// @dev Clears the value at transient `ptr`. + function clearCompat(TBytes32 storage ptr) internal { + if (block.chainid == 1) return clear(ptr); + _compat(ptr)._spacer = 0; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* ADDRESS OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a `address` in transient storage. + function tAddress(bytes32 tSlot) internal pure returns (TAddress storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a `address` in transient storage. + function tAddress(uint256 tSlot) internal pure returns (TAddress storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the value at transient `ptr`. + function get(TAddress storage ptr) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + result := tload(ptr.slot) + } + } + + /// @dev Returns the value at transient `ptr`. + function getCompat(TAddress storage ptr) internal view returns (address result) { + result = block.chainid == 1 ? get(ptr) : address(uint160(_compat(ptr)._spacer)); + } + + /// @dev Sets the value at transient `ptr`. + function set(TAddress storage ptr, address value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, shr(96, shl(96, value))) + } + } + + /// @dev Sets the value at transient `ptr`. + function setCompat(TAddress storage ptr, address value) internal { + if (block.chainid == 1) return set(ptr, value); + _compat(ptr)._spacer = uint160(value); + } + + /// @dev Clears the value at transient `ptr`. + function clear(TAddress storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, 0) + } + } + + /// @dev Clears the value at transient `ptr`. + function clearCompat(TAddress storage ptr) internal { + if (block.chainid == 1) return clear(ptr); + _compat(ptr)._spacer = 0; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BOOL OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a `bool` in transient storage. + function tBool(bytes32 tSlot) internal pure returns (TBool storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a `bool` in transient storage. + function tBool(uint256 tSlot) internal pure returns (TBool storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the value at transient `ptr`. + function get(TBool storage ptr) internal view returns (bool result) { + /// @solidity memory-safe-assembly + assembly { + result := tload(ptr.slot) + } + } + + /// @dev Returns the value at transient `ptr`. + function getCompat(TBool storage ptr) internal view returns (bool result) { + result = block.chainid == 1 ? get(ptr) : _compat(ptr)._spacer != 0; + } + + /// @dev Sets the value at transient `ptr`. + function set(TBool storage ptr, bool value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, iszero(iszero(value))) + } + } + + /// @dev Sets the value at transient `ptr`. + function setCompat(TBool storage ptr, bool value) internal { + if (block.chainid == 1) return set(ptr, value); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + sstore(ptr.slot, iszero(iszero(value))) + } + } + + /// @dev Clears the value at transient `ptr`. + function clear(TBool storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, 0) + } + } + + /// @dev Clears the value at transient `ptr`. + function clearCompat(TBool storage ptr) internal { + if (block.chainid == 1) return clear(ptr); + _compat(ptr)._spacer = 0; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* BYTES OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a `bytes` in transient storage. + function tBytes(bytes32 tSlot) internal pure returns (TBytes storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a `bytes` in transient storage. + function tBytes(uint256 tSlot) internal pure returns (TBytes storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the length of the bytes stored at transient `ptr`. + function length(TBytes storage ptr) internal view returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + result := shr(224, tload(ptr.slot)) + } + } + + /// @dev Returns the length of the bytes stored at transient `ptr`. + function lengthCompat(TBytes storage ptr) internal view returns (uint256 result) { + if (block.chainid == 1) return length(ptr); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + result := shr(224, sload(ptr.slot)) + } + } + + /// @dev Returns the bytes stored at transient `ptr`. + function get(TBytes storage ptr) internal view returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + mstore(result, 0x00) + mstore(add(result, 0x1c), tload(ptr.slot)) // Length and first `0x1c` bytes. + let n := mload(result) + let e := add(add(result, 0x20), n) + if iszero(lt(n, 0x1d)) { + mstore(0x00, ptr.slot) + let d := sub(keccak256(0x00, 0x20), result) + for { let o := add(result, 0x3c) } 1 { } { + mstore(o, tload(add(o, d))) + o := add(o, 0x20) + if iszero(lt(o, e)) { break } + } + } + mstore(e, 0) // Zeroize the slot after the string. + mstore(0x40, add(0x20, e)) // Allocate memory. + } + } + + /// @dev Returns the bytes stored at transient `ptr`. + function getCompat(TBytes storage ptr) internal view returns (bytes memory result) { + if (block.chainid == 1) return get(ptr); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + mstore(result, 0x00) + mstore(add(result, 0x1c), sload(ptr.slot)) // Length and first `0x1c` bytes. + let n := mload(result) + let e := add(add(result, 0x20), n) + if iszero(lt(n, 0x1d)) { + mstore(0x00, ptr.slot) + let d := sub(keccak256(0x00, 0x20), result) + for { let o := add(result, 0x3c) } 1 { } { + mstore(o, sload(add(o, d))) + o := add(o, 0x20) + if iszero(lt(o, e)) { break } + } + } + mstore(e, 0) // Zeroize the slot after the string. + mstore(0x40, add(0x20, e)) // Allocate memory. + } + } + + /// @dev Sets the value at transient `ptr`. + function set(TBytes storage ptr, bytes memory value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, mload(add(value, 0x1c))) + if iszero(lt(mload(value), 0x1d)) { + mstore(0x00, ptr.slot) + let e := add(add(value, 0x20), mload(value)) + let d := sub(keccak256(0x00, or(0x20, sub(0, shr(32, mload(value))))), value) + for { let o := add(value, 0x3c) } 1 { } { + tstore(add(o, d), mload(o)) + o := add(o, 0x20) + if iszero(lt(o, e)) { break } + } + } + } + } + + /// @dev Sets the value at transient `ptr`. + function setCompat(TBytes storage ptr, bytes memory value) internal { + if (block.chainid == 1) return set(ptr, value); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + sstore(ptr.slot, mload(add(value, 0x1c))) + if iszero(lt(mload(value), 0x1d)) { + mstore(0x00, ptr.slot) + let e := add(add(value, 0x20), mload(value)) + let d := sub(keccak256(0x00, or(0x20, sub(0, shr(32, mload(value))))), value) + for { let o := add(value, 0x3c) } 1 { } { + sstore(add(o, d), mload(o)) + o := add(o, 0x20) + if iszero(lt(o, e)) { break } + } + } + } + } + + /// @dev Sets the value at transient `ptr`. + function setCalldata(TBytes storage ptr, bytes calldata value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, or(shl(224, value.length), shr(32, calldataload(value.offset)))) + if iszero(lt(value.length, 0x1d)) { + mstore(0x00, ptr.slot) + let e := add(value.offset, value.length) + // forgefmt: disable-next-item + let d := add(sub(keccak256(0x00, or(0x20, sub(0, shr(32, value.length)))), + value.offset), 0x20) + for { let o := add(value.offset, 0x1c) } 1 { } { + tstore(add(o, d), calldataload(o)) + o := add(o, 0x20) + if iszero(lt(o, e)) { break } + } + } + } + } + + /// @dev Sets the value at transient `ptr`. + function setCalldataCompat(TBytes storage ptr, bytes calldata value) internal { + if (block.chainid == 1) return setCalldata(ptr, value); + ptr = _compat(ptr); + /// @solidity memory-safe-assembly + assembly { + sstore(ptr.slot, or(shl(224, value.length), shr(32, calldataload(value.offset)))) + if iszero(lt(value.length, 0x1d)) { + mstore(0x00, ptr.slot) + let e := add(value.offset, value.length) + // forgefmt: disable-next-item + let d := add(sub(keccak256(0x00, or(0x20, sub(0, shr(32, value.length)))), + value.offset), 0x20) + for { let o := add(value.offset, 0x1c) } 1 { } { + sstore(add(o, d), calldataload(o)) + o := add(o, 0x20) + if iszero(lt(o, e)) { break } + } + } + } + } + + /// @dev Clears the value at transient `ptr`. + function clear(TBytes storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(ptr.slot, 0) + } + } + + /// @dev Clears the value at transient `ptr`. + function clearCompat(TBytes storage ptr) internal { + if (block.chainid == 1) return clear(ptr); + _compat(ptr)._spacer = 0; + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* STACK OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a pointer to a stack in transient storage. + function tStack(bytes32 tSlot) internal pure returns (TStack storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns a pointer to a stack in transient storage. + function tStack(uint256 tSlot) internal pure returns (TStack storage ptr) { + /// @solidity memory-safe-assembly + assembly { + ptr.slot := tSlot + } + } + + /// @dev Returns the number of elements in the stack. + function length(TStack storage ptr) internal view returns (uint256 result) { + /// @solidity memory-safe-assembly + assembly { + result := shr(160, shl(128, tload(ptr.slot))) // Removes the base offset and stride. + } + } + + /// @dev Clears the stack at `ptr`. + /// Note: Future usage of the stack will point to a fresh transient storage region. + function clear(TStack storage ptr) internal { + /// @solidity memory-safe-assembly + assembly { + // Clears the length and increments the base pointer by `1 << 128`. + tstore(ptr.slot, shl(128, add(1, shr(128, tload(ptr.slot))))) + } + } + + /// @dev Increments the stack length by 1, and returns a pointer to the top element. + /// We don't want to call this `push` as it does not take in an element value. + /// Note: The value pointed to might not be cleared from previous usage. + function place(TStack storage ptr) internal returns (bytes32 topPtr) { + /// @solidity memory-safe-assembly + assembly { + topPtr := add(0x100000000, tload(ptr.slot)) // Increments by a stride. + tstore(ptr.slot, topPtr) + topPtr := add(mul(_STACK_BASE_SALT, ptr.slot), topPtr) + } + } + + /// @dev Returns a pointer to the top element. Returns zero if the stack is empty. + /// This method can help avoid an additional `TLOAD`. + function peek(TStack storage ptr) internal view returns (bytes32 topPtr) { + /// @solidity memory-safe-assembly + assembly { + let t := tload(ptr.slot) + topPtr := mul(iszero(iszero(shl(128, t))), add(mul(_STACK_BASE_SALT, ptr.slot), t)) + } + } + + /// @dev Returns a pointer to the top element. Reverts if the stack is empty. + function top(TStack storage ptr) internal view returns (bytes32 topPtr) { + /// @solidity memory-safe-assembly + assembly { + topPtr := tload(ptr.slot) + if iszero(topPtr) { + mstore(0x00, 0xbb704e21) // `StackIsEmpty()`. + revert(0x1c, 0x04) + } + topPtr := add(mul(_STACK_BASE_SALT, ptr.slot), topPtr) + } + } + + /// @dev Decrements the stack length by 1, returns a pointer to the top element + /// before the popping. Reverts if the stack is empty. + /// Note: Popping from the stack does NOT auto-clear the top value. + function pop(TStack storage ptr) internal returns (bytes32 lastTopPtr) { + /// @solidity memory-safe-assembly + assembly { + lastTopPtr := tload(ptr.slot) + if iszero(lastTopPtr) { + mstore(0x00, 0xbb704e21) // `StackIsEmpty()`. + revert(0x1c, 0x04) + } + tstore(ptr.slot, sub(lastTopPtr, 0x100000000)) // Decrements by a stride. + lastTopPtr := add(mul(_STACK_BASE_SALT, ptr.slot), lastTopPtr) + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* TRANSIENT REGISTRY OPERATIONS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Sets the value for the key. + /// If the key does not exist, its admin will be set to the caller. + /// If the key already exist, its value will be overwritten, + /// and the caller must be the current admin for the key. + /// Reverts with empty data if the registry has not been deployed. + function registrySet(bytes32 key, bytes memory value) internal { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) + mstore(m, 0xaac438c0) // `set(bytes32,bytes)`. + mstore(add(m, 0x20), key) + mstore(add(m, 0x40), 0x40) + let n := mload(value) + mstore(add(m, 0x60), n) + for { let i := 0 } lt(i, n) { i := add(i, 0x20) } { + mstore(add(add(m, 0x80), i), mload(add(add(value, 0x20), i))) + } + if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, add(m, 0x1c), add(n, 0x64), 0x00, 0x20))) { + revert(0x00, returndatasize()) + } + } + } + + /// @dev Returns the value for the key. + /// Reverts if the key does not exist. + /// Reverts with empty data if the registry has not been deployed. + function registryGet(bytes32 key) internal view returns (bytes memory result) { + /// @solidity memory-safe-assembly + assembly { + result := mload(0x40) + mstore(0x00, 0x8eaa6ac0) // `get(bytes32)`. + mstore(0x20, key) + if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) { + revert(0x00, returndatasize()) + } + // We can safely assume that the bytes will be containing the 0x20 offset. + returndatacopy(result, 0x20, sub(returndatasize(), 0x20)) + mstore(0x40, add(result, returndatasize())) // Allocate memory. + } + } + + /// @dev Clears the admin and the value for the key. + /// The caller must be the current admin of the key. + /// Reverts with empty data if the registry has not been deployed. + function registryClear(bytes32 key) internal { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, 0x97040a45) // `clear(bytes32)`. + mstore(0x20, key) + if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x24, 0x00, 0x20))) { + revert(0x00, returndatasize()) + } + } + } + + /// @dev Returns the admin of the key. + /// Returns `address(0)` if the key does not exist. + /// Reverts with empty data if the registry has not been deployed. + function registryAdminOf(bytes32 key) internal view returns (address result) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, 0xc5344411) // `adminOf(bytes32)`. + mstore(0x20, key) + if iszero(mul(returndatasize(), staticcall(gas(), REGISTRY, 0x1c, 0x24, 0x00, 0x20))) { + revert(0x00, returndatasize()) + } + result := mload(0x00) + } + } + + /// @dev Changes the admin of the key. + /// The caller must be the current admin of the key. + /// The new admin must not be `address(0)`. + /// Reverts with empty data if the registry has not been deployed. + function registryChangeAdmin(bytes32 key, address newAdmin) internal { + /// @solidity memory-safe-assembly + assembly { + let m := mload(0x40) // Cache the free memory pointer. + mstore(0x00, 0x053b1ca3) // `changeAdmin(bytes32,address)`. + mstore(0x20, key) + mstore(0x40, shr(96, shl(96, newAdmin))) + if iszero(mul(returndatasize(), call(gas(), REGISTRY, 0, 0x1c, 0x44, 0x00, 0x20))) { + revert(0x00, returndatasize()) + } + mstore(0x40, m) // Restore the free memory pointer. + } + } + + /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ + /* PRIVATE HELPERS */ + /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ + + /// @dev Returns a regular storage pointer used for compatibility. + function _compat(TUint256 storage ptr) private pure returns (TUint256 storage c) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _LIB_TRANSIENT_COMPAT_SLOT_SEED) + mstore(0x00, ptr.slot) + c.slot := keccak256(0x00, 0x24) + } + } + + /// @dev Returns a regular storage pointer used for compatibility. + function _compat(TInt256 storage ptr) private pure returns (TInt256 storage c) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _LIB_TRANSIENT_COMPAT_SLOT_SEED) + mstore(0x00, ptr.slot) + c.slot := keccak256(0x00, 0x24) + } + } + + /// @dev Returns a regular storage pointer used for compatibility. + function _compat(TBytes32 storage ptr) private pure returns (TBytes32 storage c) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _LIB_TRANSIENT_COMPAT_SLOT_SEED) + mstore(0x00, ptr.slot) + c.slot := keccak256(0x00, 0x24) + } + } + + /// @dev Returns a regular storage pointer used for compatibility. + function _compat(TAddress storage ptr) private pure returns (TAddress storage c) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _LIB_TRANSIENT_COMPAT_SLOT_SEED) + mstore(0x00, ptr.slot) + c.slot := keccak256(0x00, 0x24) + } + } + + /// @dev Returns a regular storage pointer used for compatibility. + function _compat(TBool storage ptr) private pure returns (TBool storage c) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _LIB_TRANSIENT_COMPAT_SLOT_SEED) + mstore(0x00, ptr.slot) + c.slot := keccak256(0x00, 0x24) + } + } + + /// @dev Returns a regular storage pointer used for compatibility. + function _compat(TBytes storage ptr) private pure returns (TBytes storage c) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x04, _LIB_TRANSIENT_COMPAT_SLOT_SEED) + mstore(0x00, ptr.slot) + c.slot := keccak256(0x00, 0x24) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Panic.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol) + +/** + * @dev Helper library for emitting standardized panic codes. + * + * ```solidity + * contract Example { + * using Panic for uint256; + * + * // Use any of the declared internal constants + * function foo() { Panic.GENERIC.panic(); } + * + * // Alternatively + * function foo() { Panic.panic(Panic.GENERIC); } + * } + * ``` + * + * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. + * + * _Available since v5.1._ + */ +// slither-disable-next-line unused-state +library Panic { + /// @dev generic / unspecified error + uint256 internal constant GENERIC = 0x00; + /// @dev used by the assert() builtin + uint256 internal constant ASSERT = 0x01; + /// @dev arithmetic underflow or overflow + uint256 internal constant UNDER_OVERFLOW = 0x11; + /// @dev division or modulo by zero + uint256 internal constant DIVISION_BY_ZERO = 0x12; + /// @dev enum conversion error + uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; + /// @dev invalid encoding in storage + uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; + /// @dev empty array pop + uint256 internal constant EMPTY_ARRAY_POP = 0x31; + /// @dev array out of bounds access + uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; + /// @dev resource error (too large allocation or too large array) + uint256 internal constant RESOURCE_ERROR = 0x41; + /// @dev calling invalid internal function + uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; + + /// @dev Reverts with a panic code. Recommended to use with + /// the internal constants with predefined codes. + function panic(uint256 code) internal pure { + assembly ("memory-safe") { + mstore(0x00, 0x4e487b71) + mstore(0x20, code) + revert(0x1c, 0x24) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +/** + * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeCast { + /** + * @dev Value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); + + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toUint248(uint256 value) internal pure returns (uint248) { + if (value > type(uint248).max) { + revert SafeCastOverflowedUintDowncast(248, value); + } + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toUint240(uint256 value) internal pure returns (uint240) { + if (value > type(uint240).max) { + revert SafeCastOverflowedUintDowncast(240, value); + } + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toUint232(uint256 value) internal pure returns (uint232) { + if (value > type(uint232).max) { + revert SafeCastOverflowedUintDowncast(232, value); + } + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toUint224(uint256 value) internal pure returns (uint224) { + if (value > type(uint224).max) { + revert SafeCastOverflowedUintDowncast(224, value); + } + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toUint216(uint256 value) internal pure returns (uint216) { + if (value > type(uint216).max) { + revert SafeCastOverflowedUintDowncast(216, value); + } + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toUint208(uint256 value) internal pure returns (uint208) { + if (value > type(uint208).max) { + revert SafeCastOverflowedUintDowncast(208, value); + } + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toUint200(uint256 value) internal pure returns (uint200) { + if (value > type(uint200).max) { + revert SafeCastOverflowedUintDowncast(200, value); + } + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toUint192(uint256 value) internal pure returns (uint192) { + if (value > type(uint192).max) { + revert SafeCastOverflowedUintDowncast(192, value); + } + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toUint184(uint256 value) internal pure returns (uint184) { + if (value > type(uint184).max) { + revert SafeCastOverflowedUintDowncast(184, value); + } + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toUint176(uint256 value) internal pure returns (uint176) { + if (value > type(uint176).max) { + revert SafeCastOverflowedUintDowncast(176, value); + } + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toUint168(uint256 value) internal pure returns (uint168) { + if (value > type(uint168).max) { + revert SafeCastOverflowedUintDowncast(168, value); + } + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toUint160(uint256 value) internal pure returns (uint160) { + if (value > type(uint160).max) { + revert SafeCastOverflowedUintDowncast(160, value); + } + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toUint152(uint256 value) internal pure returns (uint152) { + if (value > type(uint152).max) { + revert SafeCastOverflowedUintDowncast(152, value); + } + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toUint144(uint256 value) internal pure returns (uint144) { + if (value > type(uint144).max) { + revert SafeCastOverflowedUintDowncast(144, value); + } + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toUint136(uint256 value) internal pure returns (uint136) { + if (value > type(uint136).max) { + revert SafeCastOverflowedUintDowncast(136, value); + } + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + if (value > type(uint128).max) { + revert SafeCastOverflowedUintDowncast(128, value); + } + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toUint120(uint256 value) internal pure returns (uint120) { + if (value > type(uint120).max) { + revert SafeCastOverflowedUintDowncast(120, value); + } + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toUint112(uint256 value) internal pure returns (uint112) { + if (value > type(uint112).max) { + revert SafeCastOverflowedUintDowncast(112, value); + } + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toUint104(uint256 value) internal pure returns (uint104) { + if (value > type(uint104).max) { + revert SafeCastOverflowedUintDowncast(104, value); + } + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toUint96(uint256 value) internal pure returns (uint96) { + if (value > type(uint96).max) { + revert SafeCastOverflowedUintDowncast(96, value); + } + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toUint88(uint256 value) internal pure returns (uint88) { + if (value > type(uint88).max) { + revert SafeCastOverflowedUintDowncast(88, value); + } + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toUint80(uint256 value) internal pure returns (uint80) { + if (value > type(uint80).max) { + revert SafeCastOverflowedUintDowncast(80, value); + } + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toUint72(uint256 value) internal pure returns (uint72) { + if (value > type(uint72).max) { + revert SafeCastOverflowedUintDowncast(72, value); + } + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + if (value > type(uint64).max) { + revert SafeCastOverflowedUintDowncast(64, value); + } + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toUint56(uint256 value) internal pure returns (uint56) { + if (value > type(uint56).max) { + revert SafeCastOverflowedUintDowncast(56, value); + } + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toUint48(uint256 value) internal pure returns (uint48) { + if (value > type(uint48).max) { + revert SafeCastOverflowedUintDowncast(48, value); + } + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toUint40(uint256 value) internal pure returns (uint40) { + if (value > type(uint40).max) { + revert SafeCastOverflowedUintDowncast(40, value); + } + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + if (value > type(uint32).max) { + revert SafeCastOverflowedUintDowncast(32, value); + } + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toUint24(uint256 value) internal pure returns (uint24) { + if (value > type(uint24).max) { + revert SafeCastOverflowedUintDowncast(24, value); + } + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + if (value > type(uint16).max) { + revert SafeCastOverflowedUintDowncast(16, value); + } + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toUint8(uint256 value) internal pure returns (uint8) { + if (value > type(uint8).max) { + revert SafeCastOverflowedUintDowncast(8, value); + } + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(248, value); + } + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(240, value); + } + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(232, value); + } + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(224, value); + } + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(216, value); + } + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(208, value); + } + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(200, value); + } + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(192, value); + } + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(184, value); + } + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(176, value); + } + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(168, value); + } + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(160, value); + } + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(152, value); + } + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(144, value); + } + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(136, value); + } + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(128, value); + } + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(120, value); + } + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(112, value); + } + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(104, value); + } + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(96, value); + } + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(88, value); + } + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(80, value); + } + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(72, value); + } + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(64, value); + } + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(56, value); + } + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(48, value); + } + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(40, value); + } + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(32, value); + } + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(24, value); + } + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(16, value); + } + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(8, value); + } + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + if (value > uint256(type(int256).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int256(value); + } + + /** + * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. + */ + function toUint(bool b) internal pure returns (uint256 u) { + assembly ("memory-safe") { + u := iszero(iszero(b)) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/SlotDerivation.sol + +// OpenZeppelin Contracts (last updated v5.3.0) (utils/SlotDerivation.sol) +// This file was procedurally generated from scripts/generate/templates/SlotDerivation.js. + +/** + * @dev Library for computing storage (and transient storage) locations from namespaces and deriving slots + * corresponding to standard patterns. The derivation method for array and mapping matches the storage layout used by + * the solidity language / compiler. + * + * See https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays[Solidity + * docs for mappings and dynamic arrays.]. + * + * Example usage: + * ```solidity + * contract Example { + * // Add the library methods + * using StorageSlot for bytes32; + * using SlotDerivation for bytes32; + * + * // Declare a namespace + * string private constant _NAMESPACE = ""; // eg. OpenZeppelin.Slot + * + * function setValueInNamespace(uint256 key, address newValue) internal { + * _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value = newValue; + * } + * + * function getValueInNamespace(uint256 key) internal view returns (address) { + * return _NAMESPACE.erc7201Slot().deriveMapping(key).getAddressSlot().value; + * } + * } + * ``` + * + * TIP: Consider using this library along with {StorageSlot}. + * + * NOTE: This library provides a way to manipulate storage locations in a non-standard way. Tooling for checking + * upgrade safety will ignore the slots accessed through this library. + * + * _Available since v5.1._ + */ +library SlotDerivation { + /** + * @dev Derive an ERC-7201 slot from a string (namespace). + */ + function erc7201Slot(string memory namespace) internal pure returns (bytes32 slot) { + assembly ("memory-safe") { + mstore(0x00, sub(keccak256(add(namespace, 0x20), mload(namespace)), 1)) + slot := and(keccak256(0x00, 0x20), not(0xff)) + } + } + + /** + * @dev Add an offset to a slot to get the n-th element of a structure or an array. + */ + function offset(bytes32 slot, uint256 pos) internal pure returns (bytes32 result) { + unchecked { + return bytes32(uint256(slot) + pos); + } + } + + /** + * @dev Derive the location of the first element in an array from the slot where the length is stored. + */ + function deriveArray(bytes32 slot) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, slot) + result := keccak256(0x00, 0x20) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, address key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, and(key, shr(96, not(0)))) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, bool key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, iszero(iszero(key))) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, bytes32 key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, key) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, uint256 key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, key) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, int256 key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + mstore(0x00, key) + mstore(0x20, slot) + result := keccak256(0x00, 0x40) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, string memory key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + let length := mload(key) + let begin := add(key, 0x20) + let end := add(begin, length) + let cache := mload(end) + mstore(end, slot) + result := keccak256(begin, add(length, 0x20)) + mstore(end, cache) + } + } + + /** + * @dev Derive the location of a mapping element from the key. + */ + function deriveMapping(bytes32 slot, bytes memory key) internal pure returns (bytes32 result) { + assembly ("memory-safe") { + let length := mload(key) + let begin := add(key, 0x20) + let end := add(begin, length) + let cache := mload(end) + mstore(end, slot) + result := keccak256(begin, add(length, 0x20)) + mstore(end, cache) + } + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. + +/** + * @dev Library for reading and writing primitive types to specific storage slots. + * + * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. + * This library helps with reading and writing to such slots without the need for inline assembly. + * + * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. + * + * Example usage to set ERC-1967 implementation slot: + * ```solidity + * contract ERC1967 { + * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. + * bytes32 internal constant _IMPLEMENTATION_SLOT = + * 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + * + * function _getImplementation() internal view returns (address) { + * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + * } + * + * function _setImplementation(address newImplementation) internal { + * require(newImplementation.code.length > 0); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * ``` + * + * TIP: Consider using this library along with {SlotDerivation}. + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct Int256Slot { + int256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `Int256Slot` with member `value` located at `slot`. + */ + function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns a `StringSlot` with member `value` located at `slot`. + */ + function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns an `StringSlot` representation of the string storage pointer `store`. + */ + function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { + assembly ("memory-safe") { + r.slot := store.slot + } + } + + /** + * @dev Returns a `BytesSlot` with member `value` located at `slot`. + */ + function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { + assembly ("memory-safe") { + r.slot := slot + } + } + + /** + * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. + */ + function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { + assembly ("memory-safe") { + r.slot := store.slot + } + } +} + +// lib/circles-contracts-v2/src/hub/TypeDefinitions.sol + +contract TypeDefinitions { + // Type declarations + + /** + * @notice TrustMarker stores the expiry of a trust relation as uint96, + * and is iterable as a linked list of trust markers. + * @dev This is used to store the directional trust relation between two avatars, + * and the expiry of the trust relation as uint96 in unix time. + */ + struct TrustMarker { + address previous; + uint96 expiry; + } + + struct FlowEdge { + uint16 streamSinkId; + uint192 amount; + } + + struct Stream { + uint16 sourceCoordinate; + uint16[] flowEdgeIds; // todo: this can possible be packed more compactly manually, evaluate + bytes data; + } + + struct Metadata { + bytes32 metadataType; + bytes metadata; + bytes erc1155UserData; + } + + struct GroupMintMetadata { + address group; + } + + // note: Redemption does not require Metadata + + // Constants + + bytes32 internal constant METADATATYPE_GROUPMINT = keccak256("CIRCLESv2:RESERVED_DATA:CirclesGroupMint"); + bytes32 internal constant METADATATYPE_GROUPREDEEM = keccak256("CIRCLESv2:RESERVED_DATA:CirclesGroupRedeem"); +} + +// src/libs/Types.sol + +struct Subscription { + address subscriber; + address recipient; + uint256 amount; + uint256 lastRedeemed; + uint256 frequency; + Category category; +} + +enum Category { + trusted, + untrusted, + group +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol) + +/** + * @dev Standard ERC-20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens. + */ +interface IERC20Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC20InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC20InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. + * @param spender Address that may be allowed to operate on tokens without being their owner. + * @param allowance Amount of tokens a `spender` is allowed to operate with. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC20InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `spender` to be approved. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC20InvalidSpender(address spender); +} + +/** + * @dev Standard ERC-721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20. + * Used in balance queries. + * @param owner Address of the current owner of a token. + */ + error ERC721InvalidOwner(address owner); + + /** + * @dev Indicates a `tokenId` whose `owner` is the zero address. + * @param tokenId Identifier number of a token. + */ + error ERC721NonexistentToken(uint256 tokenId); + + /** + * @dev Indicates an error related to the ownership over a particular token. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param tokenId Identifier number of a token. + * @param owner Address of the current owner of a token. + */ + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC721InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC721InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param tokenId Identifier number of a token. + */ + error ERC721InsufficientApproval(address operator, uint256 tokenId); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC721InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC721InvalidOperator(address operator); +} + +/** + * @dev Standard ERC-1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens. + */ +interface IERC1155Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. + */ + error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC1155InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1155InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param owner Address of the current owner of a token. + */ + error ERC1155MissingApprovalForAll(address operator, address owner); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC1155InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1155InvalidOperator(address operator); + + /** + * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. + * Used in batch transfers. + * @param idsLength Length of the array of token identifiers + * @param valuesLength Length of the array of token amounts + */ + error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol) + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} + +// lib/circles-contracts-v2/src/circles/ICircles.sol + +interface ICircles is IDemurrage { } + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol + +// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC1155/IERC1155.sol) + +/** + * @dev Required interface of an ERC-1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[ERC]. + */ +interface IERC1155 is IERC165 { + /** + * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`. + */ + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + /** + * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all + * transfers. + */ + event TransferBatch( + address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values + ); + + /** + * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to + * `approved`. + */ + event ApprovalForAll(address indexed account, address indexed operator, bool approved); + + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + * + * If an {URI} event was emitted for `id`, the standard + * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value + * returned by {IERC1155MetadataURI-uri}. + */ + event URI(string value, uint256 indexed id); + + /** + * @dev Returns the value of tokens of token type `id` owned by `account`. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] calldata accounts, + uint256[] calldata ids + ) + external + view + returns (uint256[] memory); + + /** + * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the zero address. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address account, address operator) external view returns (bool); + + /** + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. + * + * WARNING: This function can potentially allow a reentrancy attack when transferring tokens + * to an untrusted contract, when invoking {IERC1155Receiver-onERC1155Received} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. + * + * WARNING: This function can potentially allow a reentrancy attack when transferring tokens + * to an untrusted contract, when invoking {IERC1155Receiver-onERC1155BatchReceived} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits either a {TransferSingle} or a {TransferBatch} event, depending on the length of the array arguments. + * + * Requirements: + * + * - `ids` and `values` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) + external; +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/IERC1155Receiver.sol) + +/** + * @dev Interface that must be implemented by smart contracts in order to receive + * ERC-1155 token transfers. + */ +interface IERC1155Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC-1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) + external + returns (bytes4); + + /** + * @dev Handles the receipt of a multiple ERC-1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is + * allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) + external + returns (bytes4); +} + +// src/interfaces/ISafe.sol + +interface ISafe { + function execTransactionFromModule( + address to, + uint256 value, + bytes calldata data, + Enum.Operation operation + ) + external + returns (bool success); + + function getOwners() external view returns (address[] memory); + + function enableModule(address module) external; + + function nonce() external view returns (uint256); + + function execTransaction( + address to, + uint256 value, + bytes calldata data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address payable refundReceiver, + bytes memory signatures + ) + external + returns (bool success); + + function getTransactionHash( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + uint256 _nonce + ) + external + view + returns (bytes32); +} + +// src/libs/SubscriptionLib.sol + +library SubscriptionLib { + function compute(Subscription memory subscription) internal pure returns (bytes32) { + return keccak256(abi.encode(subscription)); + } +} + +// lib/circles-contracts-v2/src/circles/Demurrage.sol + +contract Demurrage is ICirclesCompactErrors, ICirclesDemurrageErrors { + // Type declarations + + /** + * @dev Discounted balance with a last updated timestamp. + * Note: The balance is stored as a 192-bit unsigned integer. + * The last updated timestamp is stored as a 64-bit unsigned integer counting the days + * since `inflation_day_zero` (for elegance, to not start the clock in 1970 with unix time). + * We ensure that they combine to 32 bytes for a single Ethereum storage slot. + * Note: The maximum total supply of CRC is ~10^5 per human, with 10**10 humans, + * so even if all humans would pool all their tokens into a single group and then a single account + * the total resolution required is 10^(10 + 5 + 18) = 10^33 << 10**57 (~ max uint192). + */ + struct DiscountedBalance { + uint192 balance; + uint64 lastUpdatedDay; + } + + // Constants + + /** + * @notice Demurrage window reduces the resolution for calculating + * the demurrage of balances from once per second (block.timestamp) + * to once per day. + */ + uint256 private constant DEMURRAGE_WINDOW = 1 days; + + /** + * @dev Maximum value that can be stored or transferred + */ + uint256 internal constant MAX_VALUE = type(uint192).max; + + /** + * @dev Reduction factor GAMMA for applying demurrage to balances + * demurrage_balance(d) = GAMMA^d * inflationary_balance + * where 'd' is expressed in days (DEMURRAGE_WINDOW) since demurrage_day_zero, + * and GAMMA < 1. + * GAMMA_64x64 stores the numerator for the signed 128bit 64.64 + * fixed decimal point expression: + * GAMMA = GAMMA_64x64 / 2**64. + * To obtain GAMMA for a daily accounting of 7% p.a. demurrage + * => GAMMA = (0.93)^(1/365.25) + * = 0.99980133200859895743... + * and expressed in 64.64 fixed point representation: + * => GAMMA_64x64 = 18443079296116538654 + * For more details, see ./specifications/TCIP009-demurrage.md + */ + int128 internal constant GAMMA_64x64 = int128(18_443_079_296_116_538_654); + + /** + * @dev For calculating the inflationary mint amount on day `d` + * since demurrage_day_zero, a person can mint + * (1/GAMMA)^d CRC / hour + * As GAMMA is a constant, to save gas costs store the inverse + * as BETA = 1 / GAMMA. + * BETA_64x64 is the 64.64 fixed point representation: + * BETA_64x64 = 2**64 / ((0.93)^(1/365.25)) + * = 18450409579521241655 + * For more details, see ./specifications/TCIP009-demurrage.md + */ + int128 internal constant BETA_64x64 = int128(18_450_409_579_521_241_655); + + /** + * @dev ERC1155 tokens MUST be 18 decimals. + */ + uint8 internal constant DECIMALS = uint8(18); + + /** + * @dev EXA factor as 10^18 + */ + uint256 internal constant EXA = uint256(10 ** DECIMALS); + + /** + * @dev Store the signed 128-bit 64.64 representation of 1 as a constant + */ + int128 internal constant ONE_64x64 = int128(2 ** 64); + + uint8 internal constant R_TABLE_LOOKUP = uint8(14); + + // State variables + + /** + * @notice Inflation day zero stores the start of the global inflation curve + * As Circles Hub v1 was deployed on Thursday 15th October 2020 at 6:25:30 pm UTC, + * or 1602786330 unix time, in production this value MUST be set to 1602720000 unix time, + * or midnight prior of the same day of deployment, marking the start of the first day + * where there was no inflation on one CRC per hour. + */ + uint256 public inflationDayZero; + + /** + * @dev Store a lookup table T(n) for computing issuance. + * T is only accessed for minting in Hub.sol, so it is initialized in + * storage of Hub.sol during the constructor, by copying these values. + * (It is not properly intialized in a ERC20 Proxy contract, but we never need + * to access it there, so it is not a problem - it is only initialized in the + * storage of the mastercopy during deployment.) + * See ../../specifications/TCIP009-demurrage.md for more details. + */ + int128[15] internal T = [ + int128(442_721_857_769_029_238_784), + int128(885_355_760_875_826_166_476), + int128(1_327_901_726_794_166_863_126), + int128(1_770_359_772_994_355_928_788), + int128(2_212_729_916_943_227_173_193), + int128(2_655_012_176_104_144_305_282), + int128(3_097_206_567_937_001_622_606), + int128(3_539_313_109_898_224_700_583), + int128(3_981_331_819_440_771_081_628), + int128(4_423_262_714_014_130_964_135), + int128(4_865_105_811_064_327_891_331), + int128(5_306_861_128_033_919_439_986), + int128(5_748_528_682_361_997_908_993), + int128(6_190_108_491_484_191_007_805), + int128(6_631_600_572_832_662_544_739) + ]; + + /** + * @dev Store a lookup table R(n) for computing issuance and demurrage. + * This table is computed in the constructor of Hub.sol and mastercopy deployments, + * and lazily computed in the ERC20 Demurrage proxy contracts, then cached into their storage. + * The non-trivial situation for R(n) (vs T(n)) is that R is accessed + * from the ERC20 Demurrage proxy contracts, so their storage will not yet + * have been initialized with the constructor. (Counter to T which is only + * accessed for minting in Hub.sol, and as such initialized in the constructor + * of Hub.sol by Solidity by copying the python calculated values stored above.) + * + * Computing R in contract is done with .64bits precision, whereas the python computed + * table is slightly more accurate, but equal within dust (10^-18). See unit tests. + * However, we want to ensure that Hub.sol and the ERC20 Demurrage proxy contracts + * use the exact same R values (even if the difference would not matter). + * So for R we rely on the in-contract computed values. + * In the unit tests, the table of python computed values is stored in HIGHER_ACCURACY_R, + * and matched against the solidity computed values. + * See ../../specifications/TCIP009-demurrage.md for more details. + */ + int128[15] internal R; + + // Constructor + + constructor() { + // we need to fill the R table upon construction so that + // in Hub.sol personalMint has the R table available + for (uint8 i = 0; i <= R_TABLE_LOOKUP; i++) { + R[i] = ABDKMath64x64.pow(GAMMA_64x64, i); + } + } + + // Public functions + + /** + * @notice Calculate the day since inflation_day_zero for a given timestamp. + * @param _timestamp Timestamp for which to calculate the day since inflation_day_zero. + */ + function day(uint256 _timestamp) public view returns (uint64) { + // calculate which day the timestamp is in, rounding down + // note: max uint64 is 2^64 - 1, so we can safely cast the result + return uint64((_timestamp - inflationDayZero) / DEMURRAGE_WINDOW); + } + + /** + * @notice Casts an avatar address to a tokenId uint256. + * @param _avatar avatar address to convert to tokenId + */ + function toTokenId(address _avatar) public pure returns (uint256) { + return uint256(uint160(_avatar)); + } + + /** + * @notice Converts an inflationary value to a demurrage value for a given day since inflation_day_zero. + * @param _inflationaryValue Inflationary value to convert to demurrage value. + * @param _day Day since inflation_day_zero to convert the inflationary value to a demurrage value. + */ + function convertInflationaryToDemurrageValue( + uint256 _inflationaryValue, + uint64 _day + ) + public + pure + returns (uint256) + { + // calculate the demurrage value by multiplying the value by GAMMA^days + // note: GAMMA < 1, so multiplying by a power of it, returns a smaller number, + // so we lose the least significant bits, but our ground truth is the demurrage value, + // and the inflationary value is a numerical approximation (where the least significant digits + // are not reliable). + int128 r = ABDKMath64x64.pow(GAMMA_64x64, uint256(_day)); + return ABDKMath64x64.mulu(r, _inflationaryValue); + } + + /** + * @notice Converts a demurrage value to an inflationary value for a given day since inflation_day_zero. + * @param _demurrageValue Demurrage value to convert to inflationary value + * @param _dayUpdated The day the demurrage value was last updated since inflation_day_zero + */ + function convertDemurrageToInflationaryValue( + uint256 _demurrageValue, + uint64 _dayUpdated + ) + public + pure + returns (uint256) + { + // calculate the inflationary value by dividing the value by GAMMA^days + // note: GAMMA < 1, so dividing by a power of it, returns a bigger number, + // so the numerical imprecision is introduced in the least significant bits. + int128 f = ABDKMath64x64.pow(BETA_64x64, uint256(_dayUpdated)); + return ABDKMath64x64.mulu(f, _demurrageValue); + } + + // Internal functions + + /** + * @dev Calculates the discounted balance given a number of days to discount + * @param _balance balance to calculate the discounted balance of + * @param _daysDifference days of difference between the last updated day and the day of interest + */ + function _calculateDiscountedBalance(uint256 _balance, uint256 _daysDifference) internal view returns (uint256) { + if (_daysDifference == 0) { + return _balance; + } + int128 r = _calculateDemurrageFactor(_daysDifference); + return ABDKMath64x64.mulu(r, _balance); + } + + function _calculateDiscountedBalanceAndCache( + uint256 _balance, + uint256 _daysDifference + ) + internal + returns (uint256) + { + if (_daysDifference == 0) { + return _balance; + } + int128 r = _calculateDemurrageFactorAndCache(_daysDifference); + return ABDKMath64x64.mulu(r, _balance); + } + + function _calculateDemurrageFactor(uint256 _dayDifference) internal view returns (int128) { + if (_dayDifference <= R_TABLE_LOOKUP) { + // if the day difference is in the lookup table, return the value from the table + int128 demurrageFactor = R[_dayDifference]; + if (demurrageFactor != 0) { + return demurrageFactor; + } + } + // if the day difference is not in the lookup table, calculate the value + return ABDKMath64x64.pow(GAMMA_64x64, _dayDifference); + } + + function _calculateDemurrageFactorAndCache(uint256 _dayDifference) internal returns (int128) { + if (_dayDifference <= R_TABLE_LOOKUP) { + int128 demurrageFactor = R[_dayDifference]; + if (demurrageFactor == 0) { + // for proxy ERC20 contracts, the storage does not contain the R table yet + // so compute it lazily and store it in the table + demurrageFactor = ABDKMath64x64.pow(GAMMA_64x64, _dayDifference); + R[_dayDifference] = demurrageFactor; + } + return demurrageFactor; + } + // if the day difference is for older than 14 days, calculate the value + // and do not cache it + return ABDKMath64x64.pow(GAMMA_64x64, _dayDifference); + } +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol + +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol) + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[ERC]. + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/math/Math.sol + +// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol) + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + + } + + /** + * @dev Return the 512-bit addition of two uint256. + * + * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low. + */ + function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { + assembly ("memory-safe") { + low := add(a, b) + high := lt(low, a) + } + } + + /** + * @dev Return the 512-bit multiplication of two uint256. + * + * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low. + */ + function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) { + // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use + // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = high * 2²⁵⁶ + low. + assembly ("memory-safe") { + let mm := mulmod(a, b, not(0)) + low := mul(a, b) + high := sub(sub(mm, low), lt(mm, low)) + } + } + + /** + * @dev Returns the addition of two unsigned integers, with a success flag (no overflow). + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a + b; + success = c >= a; + result = c * SafeCast.toUint(success); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow). + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a - b; + success = c <= a; + result = c * SafeCast.toUint(success); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow). + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + uint256 c = a * b; + assembly ("memory-safe") { + // Only true when the multiplication doesn't overflow + // (c / a == b) || (a == 0) + success := or(eq(div(c, a), b), iszero(a)) + } + // equivalent to: success ? c : 0 + result = c * SafeCast.toUint(success); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + success = b > 0; + assembly ("memory-safe") { + // The `DIV` opcode returns zero when the denominator is 0. + result := div(a, b) + } + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { + unchecked { + success = b > 0; + assembly ("memory-safe") { + // The `MOD` opcode returns zero when the denominator is 0. + result := mod(a, b) + } + } + } + + /** + * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing. + */ + function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) { + (bool success, uint256 result) = tryAdd(a, b); + return ternary(success, result, type(uint256).max); + } + + /** + * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing. + */ + function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) { + (, uint256 result) = trySub(a, b); + return result; + } + + /** + * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing. + */ + function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) { + (bool success, uint256 result) = tryMul(a, b); + return ternary(success, result, type(uint256).max); + } + + /** + * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant. + * + * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone. + * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute + * one branch when needed, making this function more expensive. + */ + function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) { + unchecked { + // branchless ternary works because: + // b ^ (a ^ b) == a + // b ^ 0 == b + return b ^ ((a ^ b) * SafeCast.toUint(condition)); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return ternary(a > b, a, b); + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return ternary(a < b, a, b); + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + Panic.panic(Panic.DIVISION_BY_ZERO); + } + + // The following calculation ensures accurate ceiling division without overflow. + // Since a is non-zero, (a - 1) / b will not overflow. + // The largest possible result occurs when (a - 1) / b is type(uint256).max, + // but the largest value we can obtain is type(uint256).max - 1, which happens + // when a = type(uint256).max and b = 1. + unchecked { + return SafeCast.toUint(a > 0) * ((a - 1) / b + 1); + } + } + + /** + * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * + * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + (uint256 high, uint256 low) = mul512(x, y); + + // Handle non-overflow cases, 256 by 256 division. + if (high == 0) { + // Solidity will revert if denominator == 0, unlike the div opcode on its own. + // The surrounding unchecked block does not change this fact. + // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. + return low / denominator; + } + + // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. + if (denominator <= high) { + Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW)); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [high low]. + uint256 remainder; + assembly ("memory-safe") { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + high := sub(high, gt(remainder, low)) + low := sub(low, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly ("memory-safe") { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [high low] by twos. + low := div(low, twos) + + // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from high into low. + low |= high * twos; + + // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such + // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv ≡ 1 mod 2⁴. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2⁸ + inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ + inverse *= 2 - denominator * inverse; // inverse mod 2³² + inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ + inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ + inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is + // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high + // is no longer required. + result = low * inverse; + return result; + } + } + + /** + * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); + } + + /** + * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256. + */ + function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) { + unchecked { + (uint256 high, uint256 low) = mul512(x, y); + if (high >= 1 << n) { + Panic.panic(Panic.UNDER_OVERFLOW); + } + return (high << (256 - n)) | (low >> n); + } + } + + /** + * @dev Calculates x * y >> n with full precision, following the selected rounding direction. + */ + function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) { + return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0); + } + + /** + * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. + * + * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0. + * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. + * + * If the input value is not inversible, 0 is returned. + * + * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the + * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}. + */ + function invMod(uint256 a, uint256 n) internal pure returns (uint256) { + unchecked { + if (n == 0) return 0; + + // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) + // Used to compute integers x and y such that: ax + ny = gcd(a, n). + // When the gcd is 1, then the inverse of a modulo n exists and it's x. + // ax + ny = 1 + // ax = 1 + (-y)n + // ax ≡ 1 (mod n) # x is the inverse of a modulo n + + // If the remainder is 0 the gcd is n right away. + uint256 remainder = a % n; + uint256 gcd = n; + + // Therefore the initial coefficients are: + // ax + ny = gcd(a, n) = n + // 0a + 1n = n + int256 x = 0; + int256 y = 1; + + while (remainder != 0) { + uint256 quotient = gcd / remainder; + + (gcd, remainder) = ( + // The old remainder is the next gcd to try. + remainder, + // Compute the next remainder. + // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd + // where gcd is at most n (capped to type(uint256).max) + gcd - remainder * quotient + ); + + (x, y) = ( + // Increment the coefficient of a. + y, + // Decrement the coefficient of n. + // Can overflow, but the result is casted to uint256 so that the + // next value of y is "wrapped around" to a value between 0 and n - 1. + x - y * int256(quotient) + ); + } + + if (gcd != 1) return 0; // No inverse exists. + return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative. + } + } + + /** + * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`. + * + * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is + * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that + * `a**(p-2)` is the modular multiplicative inverse of a in Fp. + * + * NOTE: this function does NOT check that `p` is a prime greater than `2`. + */ + function invModPrime(uint256 a, uint256 p) internal view returns (uint256) { + unchecked { + return Math.modExp(a, p - 2, p); + } + } + + /** + * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) + * + * Requirements: + * - modulus can't be zero + * - underlying staticcall to precompile must succeed + * + * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make + * sure the chain you're using it on supports the precompiled contract for modular exponentiation + * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, + * the underlying function will succeed given the lack of a revert, but the result may be incorrectly + * interpreted as 0. + */ + function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { + (bool success, uint256 result) = tryModExp(b, e, m); + if (!success) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + return result; + } + + /** + * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). + * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying + * to operate modulo 0 or if the underlying precompile reverted. + * + * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain + * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in + * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack + * of a revert, but the result may be incorrectly interpreted as 0. + */ + function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { + if (m == 0) return (false, 0); + assembly ("memory-safe") { + let ptr := mload(0x40) + // | Offset | Content | Content (Hex) | + // |-----------|------------|--------------------------------------------------------------------| + // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | + // | 0x60:0x7f | value of b | 0x<.............................................................b> | + // | 0x80:0x9f | value of e | 0x<.............................................................e> | + // | 0xa0:0xbf | value of m | 0x<.............................................................m> | + mstore(ptr, 0x20) + mstore(add(ptr, 0x20), 0x20) + mstore(add(ptr, 0x40), 0x20) + mstore(add(ptr, 0x60), b) + mstore(add(ptr, 0x80), e) + mstore(add(ptr, 0xa0), m) + + // Given the result < m, it's guaranteed to fit in 32 bytes, + // so we can use the memory scratch space located at offset 0. + success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) + result := mload(0x00) + } + } + + /** + * @dev Variant of {modExp} that supports inputs of arbitrary length. + */ + function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { + (bool success, bytes memory result) = tryModExp(b, e, m); + if (!success) { + Panic.panic(Panic.DIVISION_BY_ZERO); + } + return result; + } + + /** + * @dev Variant of {tryModExp} that supports inputs of arbitrary length. + */ + function tryModExp( + bytes memory b, + bytes memory e, + bytes memory m + ) + internal + view + returns (bool success, bytes memory result) + { + if (_zeroBytes(m)) return (false, new bytes(0)); + + uint256 mLen = m.length; + + // Encode call args in result and move the free memory pointer + result = abi.encodePacked(b.length, e.length, mLen, b, e, m); + + assembly ("memory-safe") { + let dataPtr := add(result, 0x20) + // Write result on top of args to avoid allocating extra memory. + success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) + // Overwrite the length. + // result.length > returndatasize() is guaranteed because returndatasize() == m.length + mstore(result, mLen) + // Set the memory pointer after the returned data. + mstore(0x40, add(dataPtr, mLen)) + } + } + + /** + * @dev Returns whether the provided byte array is zero. + */ + function _zeroBytes(bytes memory byteArray) private pure returns (bool) { + for (uint256 i = 0; i < byteArray.length; ++i) { + if (byteArray[i] != 0) { + return false; + } + } + return true; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * This method is based on Newton's method for computing square roots; the algorithm is restricted to only + * using integer operations. + */ + function sqrt(uint256 a) internal pure returns (uint256) { + unchecked { + // Take care of easy edge cases when a == 0 or a == 1 + if (a <= 1) { + return a; + } + + // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a + // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between + // the current value as `ε_n = | x_n - sqrt(a) |`. + // + // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root + // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is + // bigger than any uint256. + // + // By noticing that + // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` + // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar + // to the msb function. + uint256 aa = a; + uint256 xn = 1; + + if (aa >= (1 << 128)) { + aa >>= 128; + xn <<= 64; + } + if (aa >= (1 << 64)) { + aa >>= 64; + xn <<= 32; + } + if (aa >= (1 << 32)) { + aa >>= 32; + xn <<= 16; + } + if (aa >= (1 << 16)) { + aa >>= 16; + xn <<= 8; + } + if (aa >= (1 << 8)) { + aa >>= 8; + xn <<= 4; + } + if (aa >= (1 << 4)) { + aa >>= 4; + xn <<= 2; + } + if (aa >= (1 << 2)) { + xn <<= 1; + } + + // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). + // + // We can refine our estimation by noticing that the middle of that interval minimizes the error. + // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). + // This is going to be our x_0 (and ε_0) + xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) + + // From here, Newton's method give us: + // x_{n+1} = (x_n + a / x_n) / 2 + // + // One should note that: + // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a + // = ((x_n² + a) / (2 * x_n))² - a + // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a + // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) + // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) + // = (x_n² - a)² / (2 * x_n)² + // = ((x_n² - a) / (2 * x_n))² + // ≥ 0 + // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n + // + // This gives us the proof of quadratic convergence of the sequence: + // ε_{n+1} = | x_{n+1} - sqrt(a) | + // = | (x_n + a / x_n) / 2 - sqrt(a) | + // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | + // = | (x_n - sqrt(a))² / (2 * x_n) | + // = | ε_n² / (2 * x_n) | + // = ε_n² / | (2 * x_n) | + // + // For the first iteration, we have a special case where x_0 is known: + // ε_1 = ε_0² / | (2 * x_0) | + // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) + // ≤ 2**(2*e-4) / (3 * 2**(e-1)) + // ≤ 2**(e-3) / 3 + // ≤ 2**(e-3-log2(3)) + // ≤ 2**(e-4.5) + // + // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: + // ε_{n+1} = ε_n² / | (2 * x_n) | + // ≤ (2**(e-k))² / (2 * 2**(e-1)) + // ≤ 2**(2*e-2*k) / 2**e + // ≤ 2**(e-2*k) + xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above + xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 + xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 + xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 + xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 + xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 + + // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision + // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either + // sqrt(a) or sqrt(a) + 1. + return xn - SafeCast.toUint(xn > a / xn); + } + } + + /** + * @dev Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 x) internal pure returns (uint256 r) { + // If value has upper 128 bits set, log2 result is at least 128 + r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; + // If upper 64 bits of 128-bit half set, add 64 to result + r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; + // If upper 32 bits of 64-bit half set, add 32 to result + r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; + // If upper 16 bits of 32-bit half set, add 16 to result + r |= SafeCast.toUint((x >> r) > 0xffff) << 4; + // If upper 8 bits of 16-bit half set, add 8 to result + r |= SafeCast.toUint((x >> r) > 0xff) << 3; + // If upper 4 bits of 8-bit half set, add 4 to result + r |= SafeCast.toUint((x >> r) > 0xf) << 2; + + // Shifts value right by the current result and use it as an index into this lookup table: + // + // | x (4 bits) | index | table[index] = MSB position | + // |------------|---------|-----------------------------| + // | 0000 | 0 | table[0] = 0 | + // | 0001 | 1 | table[1] = 0 | + // | 0010 | 2 | table[2] = 1 | + // | 0011 | 3 | table[3] = 1 | + // | 0100 | 4 | table[4] = 2 | + // | 0101 | 5 | table[5] = 2 | + // | 0110 | 6 | table[6] = 2 | + // | 0111 | 7 | table[7] = 2 | + // | 1000 | 8 | table[8] = 3 | + // | 1001 | 9 | table[9] = 3 | + // | 1010 | 10 | table[10] = 3 | + // | 1011 | 11 | table[11] = 3 | + // | 1100 | 12 | table[12] = 3 | + // | 1101 | 13 | table[13] = 3 | + // | 1110 | 14 | table[14] = 3 | + // | 1111 | 15 | table[15] = 3 | + // + // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the last 16 bytes. + assembly ("memory-safe") { + r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000)) + } + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 x) internal pure returns (uint256 r) { + // If value has upper 128 bits set, log2 result is at least 128 + r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7; + // If upper 64 bits of 128-bit half set, add 64 to result + r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6; + // If upper 32 bits of 64-bit half set, add 32 to result + r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5; + // If upper 16 bits of 32-bit half set, add 16 to result + r |= SafeCast.toUint((x >> r) > 0xffff) << 4; + // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8 + return (r >> 3) | SafeCast.toUint((x >> r) > 0xff); + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} + +// lib/circles-contracts-v2/src/circles/DiscountedBalances.sol + +contract DiscountedBalances is Demurrage { + // State variables + + /** + * @dev stores the discounted balances of the accounts privately. + * Mapping from Circles identifiers to accounts to the discounted balance. + */ + mapping(uint256 => mapping(address => DiscountedBalance)) internal discountedBalances; + + /** + * @dev stores the total supply for each Circles identifier + */ + mapping(uint256 => DiscountedBalance) internal discountedTotalSupplies; + + // Events + + event DiscountCost(address indexed account, uint256 indexed id, uint256 discountCost); + + // Constructor + + /** + * @dev Constructor to set the start of the global inflationary curve. + * @param _inflation_day_zero Timestamp of midgnight day zero for the global inflationary curve. + */ + constructor(uint256 _inflation_day_zero) { + inflationDayZero = _inflation_day_zero; + } + + // Public functions + + /** + * @notice Balance of a Circles identifier for a given account on a (future) day. + * @param _account Address of the account to calculate the balance of + * @param _id Circles identifier for which to calculate the balance + * @param _day Day since inflation_day_zero to calculate the balance for + * @return balanceOnDay_ The discounted balance of the account for the Circles identifier on specified day + * @return discountCost_ The discount cost of the demurrage of the balance since the last update + */ + function balanceOfOnDay( + address _account, + uint256 _id, + uint64 _day + ) + public + view + returns (uint256 balanceOnDay_, uint256 discountCost_) + { + DiscountedBalance memory discountedBalance = discountedBalances[_id][_account]; + if (_day < discountedBalance.lastUpdatedDay) { + // DiscountedBalances: day is before last updated day + // revert CirclesDemurrageDayBeforeLastUpdatedDay(_account, _id, _day, discountedBalance.lastUpdatedDay, 0); + revert CirclesErrorAddressUintArgs(_account, discountedBalance.lastUpdatedDay, 0xA0); + } + uint256 dayDifference; + unchecked { + dayDifference = _day - discountedBalance.lastUpdatedDay; + } + // Calculate the discounted balance + balanceOnDay_ = _calculateDiscountedBalance(discountedBalance.balance, dayDifference); + // Calculate the discount cost; this can be unchecked as cost is strict positive + unchecked { + discountCost_ = discountedBalance.balance - balanceOnDay_; + } + return (balanceOnDay_, discountCost_); + } + + /** + * @notice Total supply of a Circles identifier. + * @param _id Circles identifier for which to calculate the total supply + */ + function totalSupply(uint256 _id) public view returns (uint256) { + DiscountedBalance memory totalSupplyBalance = discountedTotalSupplies[_id]; + uint64 today = day(block.timestamp); + return _calculateDiscountedBalance(totalSupplyBalance.balance, today - totalSupplyBalance.lastUpdatedDay); + } + + // Internal functions + + /** + * @dev Update the balance of an account for a given Circles identifier + * @param _account Address of the account to update the balance of + * @param _id Circles identifier for which to update the balance + * @param _balance New balance to set + * @param _day Day since inflation_day_zero to set as last updated day + */ + function _updateBalance(address _account, uint256 _id, uint256 _balance, uint64 _day) internal { + if (_balance > MAX_VALUE) { + // DiscountedBalances: balance exceeds maximum value + // revert CirclesDemurrageAmountExceedsMaxUint192(_account, _id, _balance, 0); + revert CirclesErrorAddressUintArgs(_account, _id, 0x81); + } + DiscountedBalance memory discountedBalance = discountedBalances[_id][_account]; + discountedBalance.balance = uint192(_balance); + discountedBalance.lastUpdatedDay = _day; + discountedBalances[_id][_account] = discountedBalance; + } + + /** + * @dev Discount to the given day and add to the balance of an account for a given Circles identifier + * @param _account Address of the account to update the balance of + * @param _id Circles identifier for which to update the balance + * @param _value Value to add to the discounted balance + * @param _day Day since inflation_day_zero to discount the balance to + */ + function _discountAndAddToBalance(address _account, uint256 _id, uint256 _value, uint64 _day) internal { + DiscountedBalance memory discountedBalance = discountedBalances[_id][_account]; + if (_day < discountedBalance.lastUpdatedDay) { + // DiscountedBalances: day is before last updated day + // revert CirclesDemurrageDayBeforeLastUpdatedDay(_account, _id, _day, discountedBalance.lastUpdatedDay, 1); + revert CirclesErrorAddressUintArgs(_account, discountedBalance.lastUpdatedDay, 0xA1); + } + uint256 dayDifference; + unchecked { + dayDifference = _day - discountedBalance.lastUpdatedDay; + } + uint256 discountedBalanceOnDay = _calculateDiscountedBalance(discountedBalance.balance, dayDifference); + // Calculate the discount cost; this can be unchecked as cost is strict positive + unchecked { + uint256 discountCost = discountedBalance.balance - discountedBalanceOnDay; + if (discountCost > 0) { + emit IERC1155.TransferSingle(msg.sender, _account, address(0), _id, discountCost); + emit DiscountCost(_account, _id, discountCost); + } + } + uint256 updatedBalance = discountedBalanceOnDay + _value; + if (updatedBalance > MAX_VALUE) { + // DiscountedBalances: balance exceeds maximum value + // revert CirclesDemurrageAmountExceedsMaxUint190(_account, _id, updatedBalance, 1); + revert CirclesErrorAddressUintArgs(_account, _id, 0x82); + } + discountedBalance.balance = uint192(updatedBalance); + discountedBalance.lastUpdatedDay = _day; + discountedBalances[_id][_account] = discountedBalance; + } +} + +// lib/circles-contracts-v2/src/hub/IHub.sol + +interface IHubV2_0 is IERC1155, ICircles { + function avatars(address avatar) external view returns (address); + function isHuman(address avatar) external view returns (bool); + function isGroup(address avatar) external view returns (bool); + function isOrganization(address avatar) external view returns (bool); + + function migrate(address owner, address[] calldata avatars, uint256[] calldata amounts) external; + function mintPolicies(address avatar) external view returns (address); + function burn(uint256 id, uint256 amount, bytes calldata data) external; + + function operateFlowMatrix( + address[] calldata _flowVertices, + TypeDefinitions.FlowEdge[] calldata _flow, + TypeDefinitions.Stream[] calldata _streams, + bytes calldata _packedCoordinates + ) + external; +} + +// src/interfaces/IHub.sol + +interface IHubV2_1 is IERC1155, ICircles { + function avatars(address avatar) external view returns (address); + function isHuman(address avatar) external view returns (bool); + function isGroup(address avatar) external view returns (bool); + function isOrganization(address avatar) external view returns (bool); + + function groupMint( + address _group, + address[] calldata _collateralAvatars, + uint256[] calldata _amounts, + bytes calldata _data + ) + external; + + function migrate(address owner, address[] calldata avatars, uint256[] calldata amounts) external; + function mintPolicies(address avatar) external view returns (address); + + function operateFlowMatrix( + address[] calldata _flowVertices, + TypeDefinitions.FlowEdge[] calldata _flow, + TypeDefinitions.Stream[] calldata _streams, + bytes calldata _packedCoordinates + ) + external; +} + +// lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Arrays.sol + +// OpenZeppelin Contracts (last updated v5.3.0) (utils/Arrays.sol) +// This file was procedurally generated from scripts/generate/templates/Arrays.js. + +/** + * @dev Collection of functions related to array types. + */ +library Arrays { + using SlotDerivation for bytes32; + using StorageSlot for bytes32; + + /** + * @dev Sort an array of uint256 (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the + * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe + * way. + */ + function sort( + uint256[] memory array, + function(uint256, uint256) pure returns (bool) comp + ) + internal + pure + returns (uint256[] memory) + { + _quickSort(_begin(array), _end(array), comp); + return array; + } + + /** + * @dev Variant of {sort} that sorts an array of uint256 in increasing order. + */ + function sort(uint256[] memory array) internal pure returns (uint256[] memory) { + sort(array, Comparators.lt); + return array; + } + + /** + * @dev Sort an array of address (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the + * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe + * way. + */ + function sort( + address[] memory array, + function(address, address) pure returns (bool) comp + ) + internal + pure + returns (address[] memory) + { + sort(_castToUint256Array(array), _castToUint256Comp(comp)); + return array; + } + + /** + * @dev Variant of {sort} that sorts an array of address in increasing order. + */ + function sort(address[] memory array) internal pure returns (address[] memory) { + sort(_castToUint256Array(array), Comparators.lt); + return array; + } + + /** + * @dev Sort an array of bytes32 (in memory) following the provided comparator function. + * + * This function does the sorting "in place", meaning that it overrides the input. The object is returned for + * convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array. + * + * NOTE: this function's cost is `O(n · log(n))` in average and `O(n²)` in the worst case, with n the length of the + * array. Using it in view functions that are executed through `eth_call` is safe, but one should be very careful + * when executing this as part of a transaction. If the array being sorted is too large, the sort operation may + * consume more gas than is available in a block, leading to potential DoS. + * + * IMPORTANT: Consider memory side-effects when using custom comparator functions that access memory in an unsafe + * way. + */ + function sort( + bytes32[] memory array, + function(bytes32, bytes32) pure returns (bool) comp + ) + internal + pure + returns (bytes32[] memory) + { + sort(_castToUint256Array(array), _castToUint256Comp(comp)); + return array; + } + + /** + * @dev Variant of {sort} that sorts an array of bytes32 in increasing order. + */ + function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) { + sort(_castToUint256Array(array), Comparators.lt); + return array; + } + + /** + * @dev Performs a quick sort of a segment of memory. The segment sorted starts at `begin` (inclusive), and stops + * at end (exclusive). Sorting follows the `comp` comparator. + * + * Invariant: `begin <= end`. This is the case when initially called by {sort} and is preserved in subcalls. + * + * IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should + * be used only if the limits are within a memory array. + */ + function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure { + unchecked { + if (end - begin < 0x40) return; + + // Use first element as pivot + uint256 pivot = _mload(begin); + // Position where the pivot should be at the end of the loop + uint256 pos = begin; + + for (uint256 it = begin + 0x20; it < end; it += 0x20) { + if (comp(_mload(it), pivot)) { + // If the value stored at the iterator's position comes before the pivot, we increment the + // position of the pivot and move the value there. + pos += 0x20; + _swap(pos, it); + } + } + + _swap(begin, pos); // Swap pivot into place + _quickSort(begin, pos, comp); // Sort the left side of the pivot + _quickSort(pos + 0x20, end, comp); // Sort the right side of the pivot + } + } + + /** + * @dev Pointer to the memory location of the first element of `array`. + */ + function _begin(uint256[] memory array) private pure returns (uint256 ptr) { + assembly ("memory-safe") { + ptr := add(array, 0x20) + } + } + + /** + * @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word + * that comes just after the last element of the array. + */ + function _end(uint256[] memory array) private pure returns (uint256 ptr) { + unchecked { + return _begin(array) + array.length * 0x20; + } + } + + /** + * @dev Load memory word (as a uint256) at location `ptr`. + */ + function _mload(uint256 ptr) private pure returns (uint256 value) { + assembly { + value := mload(ptr) + } + } + + /** + * @dev Swaps the elements memory location `ptr1` and `ptr2`. + */ + function _swap(uint256 ptr1, uint256 ptr2) private pure { + assembly { + let value1 := mload(ptr1) + let value2 := mload(ptr2) + mstore(ptr1, value2) + mstore(ptr2, value1) + } + } + + /// @dev Helper: low level cast address memory array to uint256 memory array + function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) { + assembly { + output := input + } + } + + /// @dev Helper: low level cast bytes32 memory array to uint256 memory array + function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) { + assembly { + output := input + } + } + + /// @dev Helper: low level cast address comp function to uint256 comp function + function _castToUint256Comp(function(address, address) pure returns (bool) input) + private + pure + returns (function(uint256, uint256) pure returns (bool) output) + { + assembly { + output := input + } + } + + /// @dev Helper: low level cast bytes32 comp function to uint256 comp function + function _castToUint256Comp(function(bytes32, bytes32) pure returns (bool) input) + private + pure + returns (function(uint256, uint256) pure returns (bool) output) + { + assembly { + output := input + } + } + + /** + * @dev Searches a sorted `array` and returns the first index that contains + * a value greater or equal to `element`. If no such index exists (i.e. all + * values in the array are strictly less than `element`), the array length is + * returned. Time complexity O(log n). + * + * NOTE: The `array` is expected to be sorted in ascending order, and to + * contain no repeated elements. + * + * IMPORTANT: Deprecated. This implementation behaves as {lowerBound} but lacks + * support for repeated elements in the array. The {lowerBound} function should + * be used instead. + */ + function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeAccess(array, mid).value > element) { + high = mid; + } else { + low = mid + 1; + } + } + + // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. + if (low > 0 && unsafeAccess(array, low - 1).value == element) { + return low - 1; + } else { + return low; + } + } + + /** + * @dev Searches an `array` sorted in ascending order and returns the first + * index that contains a value greater or equal than `element`. If no such index + * exists (i.e. all values in the array are strictly less than `element`), the array + * length is returned. Time complexity O(log n). + * + * See C++'s https://en.cppreference.com/w/cpp/algorithm/lower_bound[lower_bound]. + */ + function lowerBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeAccess(array, mid).value < element) { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } else { + high = mid; + } + } + + return low; + } + + /** + * @dev Searches an `array` sorted in ascending order and returns the first + * index that contains a value strictly greater than `element`. If no such index + * exists (i.e. all values in the array are strictly less than `element`), the array + * length is returned. Time complexity O(log n). + * + * See C++'s https://en.cppreference.com/w/cpp/algorithm/upper_bound[upper_bound]. + */ + function upperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeAccess(array, mid).value > element) { + high = mid; + } else { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } + } + + return low; + } + + /** + * @dev Same as {lowerBound}, but with an array in memory. + */ + function lowerBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeMemoryAccess(array, mid) < element) { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } else { + high = mid; + } + } + + return low; + } + + /** + * @dev Same as {upperBound}, but with an array in memory. + */ + function upperBoundMemory(uint256[] memory array, uint256 element) internal pure returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeMemoryAccess(array, mid) > element) { + high = mid; + } else { + // this cannot overflow because mid < high + unchecked { + low = mid + 1; + } + } + } + + return low; + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) { + bytes32 slot; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).getAddressSlot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) { + bytes32 slot; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).getBytes32Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) { + bytes32 slot; + assembly ("memory-safe") { + slot := arr.slot + } + return slot.deriveArray().offset(pos).getUint256Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(bytes32[] memory arr, uint256 pos) internal pure returns (bytes32 res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(address[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(bytes32[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } + + /** + * @dev Helper to set the length of a dynamic array. Directly writing to `.length` is forbidden. + * + * WARNING: this does not clear elements if length is reduced, of initialize elements if length is increased. + */ + function unsafeSetLength(uint256[] storage array, uint256 len) internal { + assembly ("memory-safe") { + sstore(array.slot, len) + } + } +} + +// src/libs/CirclesLib.sol + +library CirclesLib { + using LibBytes for bytes; + + /// @notice Read bytes[start:end] from calldata and turn them into a uint256. + /// @param data The full byte array in calldata. + /// @param start The starting index (inclusive) of the slice. + /// @param end The ending index (exclusive) of the slice. + /// @return result The integer value of the slice. + function slice(bytes memory data, uint256 start, uint256 end) internal pure returns (uint256 result) { + bytes memory window = data.slice(start, end); + for (uint256 i = 0; i < window.length; i++) { + result = (result << 8) | uint8(window[i]); + } + } + + /// @notice Verify that every flow edge in the given stream routes to the specified recipient. + /// @param streams A Stream struct whose flow edge ids define how many edges to check. + /// @param recipient The address that each to index must match. + /// @param flowVertices The list of all addresses (vertices) used to resolve each to index. + /// @param coordinates Packed coordinates for this stream. + /// @return success True if every extracted to address equals `recipient`, otherwise false. + function checkRecipients( + TypeDefinitions.Stream[] memory streams, + address recipient, + address[] memory flowVertices, + bytes memory coordinates + ) + internal + pure + returns (bool) + { + TypeDefinitions.Stream memory stream = streams[streams.length - 1]; + uint256 edgeCount = stream.flowEdgeIds.length; + for (uint256 i = 0; i < edgeCount; i++) { + uint256 start = 6 * stream.flowEdgeIds[i] + 4; + uint256 toIndex = slice(coordinates, start, start + 2); + if (flowVertices[toIndex] != recipient) return false; + } + return true; + } + + function checkSource( + TypeDefinitions.Stream[] memory streams, + uint256 sourceCoordinate + ) + internal + pure + returns (bool success) + { + for (uint256 i; i < streams.length; ++i) { + if (streams[i].sourceCoordinate != sourceCoordinate) return false; + } + return true; + } + + /// @notice Sum all flow amount entries where stream sink ID is 1. + /// @param flow An array of FlowEdge structs. + /// @return amount The total of all `amount` fields whose `streamSinkId` equals 1. + function extractAmount(TypeDefinitions.FlowEdge[] memory flow) internal pure returns (uint256 amount) { + for (uint256 i = 0; i < flow.length; i++) { + if (flow[i].streamSinkId == 1) { + amount += flow[i].amount; + } + } + } +} + +// lib/circles-contracts-v2/src/circles/ERC1155.sol + +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol) + +/** + * @dev Implementation of the basic standard multi-token for demurraged and inflationary balances. + * See https://eips.ethereum.org/EIPS/eip-1155 + * This code is modified from the open-zeppelin implementation v5.0.0: + * https://github.com/OpenZeppelin/openzeppelin-contracts/ + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + */ +abstract contract ERC1155 is DiscountedBalances, Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors { + // Type declarations + + using Arrays for uint256[]; + using Arrays for address[]; + + // State variables + + mapping(address account => mapping(address operator => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + // Constructor + + /** + * @dev See {_setURI}. + */ + constructor(string memory _newuri) { + _setURI(_newuri); + } + + // Public functions + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return _interfaceId == type(IERC1155).interfaceId || _interfaceId == type(IERC1155MetadataURI).interfaceId + || super.supportsInterface(_interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256 /* id */ ) public view virtual returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + */ + function balanceOf(address _account, uint256 _id) public view returns (uint256) { + (uint256 balance,) = balanceOfOnDay(_account, _id, day(block.timestamp)); + return balance; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch(address[] memory _accounts, uint256[] memory _ids) public view returns (uint256[] memory) { + if (_accounts.length != _ids.length) { + revert ERC1155InvalidArrayLength(_ids.length, _accounts.length); + } + + uint64 today = day(block.timestamp); + + uint256[] memory batchBalances = new uint256[](_accounts.length); + + for (uint256 i = 0; i < _accounts.length; ++i) { + (batchBalances[i],) = balanceOfOnDay(_accounts.unsafeMemoryAccess(i), _ids.unsafeMemoryAccess(i), today); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address _operator, bool _approved) public { + _setApprovalForAll(_msgSender(), _operator, _approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address _account, address _operator) public view returns (bool) { + return _operatorApprovals[_account][_operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) public { + address sender = _msgSender(); + if (_from != sender && !isApprovedForAll(_from, sender)) { + revert ERC1155MissingApprovalForAll(sender, _from); + } + _safeTransferFrom(_from, _to, _id, _value, _data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] memory _ids, + uint256[] memory _values, + bytes memory _data + ) + public + virtual + { + address sender = _msgSender(); + if (_from != sender && !isApprovedForAll(_from, sender)) { + revert ERC1155MissingApprovalForAll(sender, _from); + } + _safeBatchTransferFrom(_from, _to, _ids, _values, _data); + } + + // Internal functions + + /** + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from` + * (or `to`) is the zero address. + * + * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received} + * or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value. + * - `ids` and `values` must have the same length. + * + * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead. + */ + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual { + if (ids.length != values.length) { + revert ERC1155InvalidArrayLength(ids.length, values.length); + } + + address operator = _msgSender(); + + uint64 today = day(block.timestamp); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids.unsafeMemoryAccess(i); + uint256 value = values.unsafeMemoryAccess(i); + + if (from != address(0)) { + (uint256 fromBalance, uint256 discountCost) = balanceOfOnDay(from, id, today); + if (fromBalance < value) { + revert ERC1155InsufficientBalance(from, fromBalance, value, id); + } + if (discountCost > 0) { + emit TransferSingle(operator, from, address(0), id, discountCost); + emit DiscountCost(from, id, discountCost); + } + unchecked { + // Overflow not possible: value <= fromBalance + _updateBalance(from, id, fromBalance - value, today); + } + } + + if (to != address(0)) { + _discountAndAddToBalance(to, id, value, today); + } + } + + if (ids.length == 1) { + uint256 id = ids.unsafeMemoryAccess(0); + uint256 value = values.unsafeMemoryAccess(0); + emit TransferSingle(operator, from, to, id, value); + } else { + emit TransferBatch(operator, from, to, ids, values); + } + } + + /** + * @dev Version of {_update} that performs the token acceptance check by calling + * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it + * contains code (eg. is a smart contract at the moment of execution). + * + * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any + * update to the contract state after this function would break the check-effect-interaction pattern. Consider + * overriding {_update} instead. + */ + function _updateWithAcceptanceCheck( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) + internal + virtual + { + _update(from, to, ids, values); + _acceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev do the ERC1155 token acceptance check to the receiver + */ + function _acceptanceCheck( + address _from, + address _to, + uint256[] memory _ids, + uint256[] memory _values, + bytes memory _data + ) + internal + { + if (_to != address(0)) { + address operator = _msgSender(); + if (_ids.length == 1) { + uint256 id = _ids.unsafeMemoryAccess(0); + uint256 value = _values.unsafeMemoryAccess(0); + _doSafeTransferAcceptanceCheck(operator, _from, _to, id, value, _data); + } else { + _doSafeBatchTransferAcceptanceCheck(operator, _from, _to, _ids, _values, _data); + } + } + } + + /** + * @dev Transfers a `value` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + * - `ids` and `values` must have the same length. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) + internal + { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + _updateWithAcceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the values in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory _newuri) internal virtual { + _uri = _newuri; + } + + /** + * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `_doAcceptanceCheck` is true, it will perform ERC1155 acceptance check, otherwise only update + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address to, uint256 id, uint256 value, bytes memory data, bool _doAcceptanceCheck) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + if (_doAcceptanceCheck) { + _updateWithAcceptanceCheck(address(0), to, ids, values, data); + } else { + _update(address(0), to, ids, values); + } + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `values` must have the same length. + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + // function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal { + // if (to == address(0)) { + // revert ERC1155InvalidReceiver(address(0)); + // } + // _updateWithAcceptanceCheck(address(0), to, ids, values, data); + // } + + /** + * @dev Destroys a `value` amount of tokens of type `id` from `from` + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + */ + function _burn(address from, uint256 id, uint256 value) internal { + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + * - `ids` and `values` must have the same length. + * // + */ + // function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal { + // if (from == address(0)) { + // revert ERC1155InvalidSender(address(0)); + // } + // _updateWithAcceptanceCheck(from, address(0), ids, values, ""); + // } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the zero address. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + if (operator == address(0)) { + revert ERC1155InvalidOperator(address(0)); + } + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Creates an array in memory with only one value for each of the elements provided. + */ + function _asSingletonArrays( + uint256 element1, + uint256 element2 + ) + internal + pure + returns (uint256[] memory array1, uint256[] memory array2) + { + /// @solidity memory-safe-assembly + assembly { + // Load the free memory pointer + array1 := mload(0x40) + // Set array length to 1 + mstore(array1, 1) + // Store the single element at the next word after the length (where content starts) + mstore(add(array1, 0x20), element1) + + // Repeat for next array locating it right after the first array + array2 := add(array1, 0x40) + mstore(array2, 1) + mstore(add(array2, 0x20), element2) + + // Update the free memory pointer by pointing after the second array + mstore(0x40, add(array2, 0x40)) + } + } + + // Private functions + + /** + * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address + * if it contains code at the moment of execution. + */ + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 value, + bytes memory data + ) + private + { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + // Tokens rejected + revert ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-ERC1155Receiver implementer + revert ERC1155InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } + + /** + * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address + * if it contains code at the moment of execution. + */ + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) + private + { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns (bytes4 response) + { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + // Tokens rejected + revert ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-ERC1155Receiver implementer + revert ERC1155InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } +} + +// src/SubscriptionModule.sol + +contract SubscriptionModule { + /*////////////////////////////////////////////////////////////// + LIBRARIES + //////////////////////////////////////////////////////////////*/ + + using SubscriptionLib for Subscription; + + using EnumerableSetLib for EnumerableSetLib.Bytes32Set; + + using CirclesLib for TypeDefinitions.FlowEdge[]; + + using CirclesLib for TypeDefinitions.Stream[]; + + using LibTransient for LibTransient.TUint256; + + /*////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////*/ + + string public constant NAME = "Subscription Module"; + string public constant VERSION = "0.1.0"; + + address public constant HUB = 0xc12C1E50ABB450d6205Ea2C3Fa861b3B834d13e8; + + address public constant MULTISEND = 0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526; + + bytes32 internal constant T_REDEEMABLE_AMOUNT = 0x70bfbb43a5ce660914e09d1b48fcc488982d5981137b973eac35b0592a414e90; + + mapping(bytes32 id => Subscription subscription) internal _subscriptions; + + mapping(address subscriber => EnumerableSetLib.Bytes32Set) internal ids; + + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event SubscriptionCreated( + bytes32 indexed id, + address indexed subscriber, + address indexed recipient, + uint256 amount, + uint256 frequency, + Category category + ); + + event Redeemed(bytes32 indexed id, address indexed subscriber, address indexed recipient, uint256 nextRedeemAt); + + event RecipientUpdated(bytes32 indexed id, address indexed oldRecipient, address indexed newRecipient); + + event Unsubscribed(bytes32 indexed id, address indexed subscriber); + + /*////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function subscribe( + address recipient, + uint256 amount, + uint256 frequency, + Category category + ) + external + returns (bytes32 id) + { + require(frequency > 0, Errors.InvalidFrequency()); + Subscription memory sub = Subscription({ + subscriber: msg.sender, + recipient: recipient, + amount: amount, + lastRedeemed: block.timestamp - frequency, + frequency: frequency, + category: category + }); + id = sub.compute(); + _subscribe(id, sub); + emit SubscriptionCreated(id, msg.sender, recipient, amount, frequency, category); + } + + function redeem(bytes32 id, bytes calldata data) external { + Subscription memory sub = _subscriptions[id]; + require(sub.subscriber != address(0), Errors.IdentifierNonexistent()); + + uint256 periods = (block.timestamp - sub.lastRedeemed) / sub.frequency; + require(periods >= 1, Errors.NotRedeemable()); + + LibTransient.tUint256(T_REDEEMABLE_AMOUNT).set(periods * sub.amount); + sub.lastRedeemed += periods * sub.frequency; + _subscriptions[id] = sub; + + if (sub.category == Category.group) { + _redeemGroup(id, sub); + } else if (sub.category == Category.trusted) { + ( + address[] memory flowVertices, + TypeDefinitions.FlowEdge[] memory flow, + TypeDefinitions.Stream[] memory streams, + bytes memory packedCoordinates, + uint256 sourceCoordinate + ) = abi.decode(data, (address[], TypeDefinitions.FlowEdge[], TypeDefinitions.Stream[], bytes, uint256)); + _redeemTrusted(id, sub, flowVertices, flow, streams, packedCoordinates, sourceCoordinate); + } else if (sub.category == Category.untrusted) { + _redeemUntrusted(id, sub); + } else { + revert Errors.InvalidCategory(); + } + } + + function unsubscribe(bytes32 id) external { + _unsubscribe(msg.sender, id); + } + + function unsubscribeMany(bytes32[] calldata _ids) external { + for (uint256 i; i < _ids.length; ++i) { + _unsubscribe(msg.sender, _ids[i]); + } + } + + function updateRecipient(bytes32 id, address newRecipient) external { + Subscription storage sub = _subscriptions[id]; + require(sub.recipient == msg.sender, Errors.OnlyRecipient()); + sub.recipient = newRecipient; + emit RecipientUpdated(id, msg.sender, newRecipient); + } + + /*////////////////////////////////////////////////////////////// + USER-FACING CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function getSubscription(bytes32 id) external view returns (Subscription memory) { + return _subscriptions[id]; + } + + function getSubscriptionIds(address subscriber) external view returns (bytes32[] memory) { + return ids[subscriber].values(); + } + + function isValidOrRedeemable(bytes32 id) public view returns (uint256) { + if (_subscriptions[id].subscriber == address(0)) return 0; + Subscription memory sub = _subscriptions[id]; + return (block.timestamp - sub.lastRedeemed) / sub.frequency * sub.amount; + } + + /*////////////////////////////////////////////////////////////// + INTERNAL NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function _subscribe(bytes32 id, Subscription memory sub) internal { + require(_subscriptions[id].subscriber == address(0), Errors.IdentifierExists()); + _subscriptions[id] = sub; + ids[sub.subscriber].add(id); + } + + function _unsubscribe(address caller, bytes32 id) internal { + Subscription memory sub = _subscriptions[id]; + require(sub.subscriber == caller, Errors.OnlySubscriber()); + delete _subscriptions[id]; + ids[sub.subscriber].remove(id); + emit Unsubscribed(id, sub.subscriber); + } + + function _redeemGroup(bytes32 id, Subscription memory sub) internal { + address[] memory collateralAvatars = new address[](1); + collateralAvatars[0] = sub.subscriber; + + uint256[] memory amounts = new uint256[](1); + amounts[0] = sub.amount; + + require( + ISafe(sub.subscriber).execTransactionFromModule( + HUB, + 0, + abi.encodeCall(IHubV2_1.groupMint, (sub.recipient, collateralAvatars, amounts, "")), + Enum.Operation.Call + ), + Errors.ExecutionFailed() + ); + + emit Redeemed(id, sub.subscriber, sub.recipient, sub.lastRedeemed + sub.frequency); + LibTransient.tUint256(T_REDEEMABLE_AMOUNT).clear(); + } + + function _redeemTrusted( + bytes32 id, + Subscription memory sub, + address[] memory flowVertices, + TypeDefinitions.FlowEdge[] memory flow, + TypeDefinitions.Stream[] memory streams, + bytes memory packedCoordinates, + uint256 sourceCoordinate + ) + internal + { + require(flowVertices[sourceCoordinate] == sub.subscriber, Errors.InvalidSubscriber()); + + require(streams.checkSource(sourceCoordinate), Errors.InvalidStreamSource()); + + require(streams.checkRecipients(sub.recipient, flowVertices, packedCoordinates), Errors.InvalidRecipient()); + + require(flow.extractAmount() == LibTransient.tUint256(T_REDEEMABLE_AMOUNT).get(), Errors.InvalidAmount()); + + require( + ISafe(sub.subscriber).execTransactionFromModule( + HUB, + 0, + abi.encodeCall(IHubV2_1.operateFlowMatrix, (flowVertices, flow, streams, packedCoordinates)), + Enum.Operation.Call + ), + Errors.ExecutionFailed() + ); + + emit Redeemed(id, sub.subscriber, sub.recipient, sub.lastRedeemed + sub.frequency); + LibTransient.tUint256(T_REDEEMABLE_AMOUNT).clear(); + } + + function _redeemUntrusted(bytes32 id, Subscription memory sub) internal { + require( + ISafe(sub.subscriber).execTransactionFromModule( + HUB, + 0, + abi.encodeCall( + ERC1155.safeTransferFrom, + ( + sub.subscriber, + sub.recipient, + _toTokenId(sub.subscriber), + LibTransient.tUint256(T_REDEEMABLE_AMOUNT).get(), + "" + ) + ), + Enum.Operation.Call + ), + Errors.ExecutionFailed() + ); + + emit Redeemed(id, sub.subscriber, sub.recipient, sub.lastRedeemed + sub.frequency); + LibTransient.tUint256(T_REDEEMABLE_AMOUNT).clear(); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function _toTokenId(address _avatar) internal pure returns (uint256) { + return uint256(uint160(_avatar)); + } +} diff --git a/src/SubscriptionModule.sol b/src/SubscriptionModule.sol index 729d4ad..8765bad 100644 --- a/src/SubscriptionModule.sol +++ b/src/SubscriptionModule.sol @@ -56,7 +56,7 @@ contract SubscriptionModule { address indexed subscriber, address indexed recipient, uint256 amount, - uint256 nextRedeemAt, + uint256 frequency, Category category ); @@ -90,7 +90,7 @@ contract SubscriptionModule { }); id = sub.compute(); _subscribe(id, sub); - emit SubscriptionCreated(id, msg.sender, recipient, amount, block.timestamp, category); + emit SubscriptionCreated(id, msg.sender, recipient, amount, frequency, category); } function redeem(bytes32 id, bytes calldata data) external { diff --git a/test/unit/fuzz/subscribe/subscribe.t.sol b/test/unit/fuzz/subscribe/subscribe.t.sol index 8cf8eff..a80ef3e 100644 --- a/test/unit/fuzz/subscribe/subscribe.t.sol +++ b/test/unit/fuzz/subscribe/subscribe.t.sol @@ -98,7 +98,7 @@ contract Subscribe_Unit_Fuzz_Test is Base_Test { vm.expectEmit(); emit SubscriptionModule.SubscriptionCreated( - sub.compute(), users.subscriber, recipient, amount, vm.getBlockTimestamp(), Category.trusted + sub.compute(), users.subscriber, recipient, amount, frequency, Category.trusted ); bytes32 id = module.subscribe(recipient, amount, frequency, Category.trusted);