Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x36b49ebF089BE8860d7fC60f2553461E9Cc8e9e2
Balance 0 ETH
Nonce 1
Code Size 19595 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

19595 bytes
0x60806040526004361061026a5760003560e01c80636ca9836011610153578063ac9650d8116100cb578063d42b860d1161007f578063e6c893c011610064578063e6c893c014610783578063e9592945146107a3578063f3995c67146107db57600080fd5b8063d42b860d14610736578063e30c39781461075657600080fd5b8063c2e3140a116100b0578063c2e3140a14610686578063c38a23fd14610699578063c45a01551461070257600080fd5b8063ac9650d814610646578063ae4766071461066657600080fd5b806388d41b0211610122578063927dd6bc11610107578063927dd6bc146105ea57806392e226a61461060a578063a5ca5c041461062657600080fd5b806388d41b02146105905780638da5cb5b146105bd57600080fd5b80636ca98360146105105780637134bf5c14610530578063748b259c14610550578063875efaae1461057057600080fd5b806343e002c4116101e65780635cb258dd116101b557806363f41f821161019a57806363f41f821461048b578063696bf4b7146104ab57806369f6d9b3146104f057600080fd5b80635cb258dd1461044b5780635fb87d1c1461046b57600080fd5b806343e002c4146103c957806346269502146103e95780634ba58cc1146104095780634e71e0c81461043657600080fd5b80631e72063c1161023d5780632102d9e2116102225780632102d9e214610351578063220bd3161461037157806341725efa1461039157600080fd5b80631e72063c146103115780631f27f9271461033157600080fd5b8063078dfbe71461026f578063095ca64c14610291578063172693e7146102c45780631c7748b1146102f1575b600080fd5b34801561027b57600080fd5b5061028f61028a366004614153565b6107ee565b005b34801561029d57600080fd5b506102b16102ac366004614198565b6109df565b6040519081526020015b60405180910390f35b3480156102d057600080fd5b506102e46102df3660046141e9565b610af8565b6040516102bb919061427c565b3480156102fd57600080fd5b506102b161030c36600461428f565b610bb1565b34801561031d57600080fd5b506102b161032c3660046141e9565b610e2a565b34801561033d57600080fd5b506102e461034c3660046141e9565b610ec1565b34801561035d57600080fd5b506102b161036c3660046141e9565b610f64565b34801561037d57600080fd5b5061028f61038c3660046142c8565b611072565b34801561039d57600080fd5b506102b16103ac36600461428f565b600560209081526000928352604080842090915290825290205481565b3480156103d557600080fd5b506102b16103e43660046141e9565b6112ae565b3480156103f557600080fd5b5061028f6104043660046141e9565b6112cb565b34801561041557600080fd5b506102b16104243660046141e9565b60046020526000908152604090205481565b34801561044257600080fd5b5061028f6113f7565b34801561045757600080fd5b506102b1610466366004614307565b61150e565b34801561047757600080fd5b5061028f61048636600461435a565b6117d1565b34801561049757600080fd5b506102b16104a63660046143ab565b611a44565b3480156104b757600080fd5b506104cb6104c63660046141e9565b611b8d565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102bb565b3480156104fc57600080fd5b506102e461050b3660046141e9565b611c49565b34801561051c57600080fd5b506102b161052b36600461440f565b611cec565b34801561053c57600080fd5b506102e461054b3660046141e9565b611e7d565b34801561055c57600080fd5b506102b161056b36600461428f565b611f20565b34801561057c57600080fd5b506102b161058b366004614451565b6120eb565b34801561059c57600080fd5b506102b16105ab3660046141e9565b60036020526000908152604090205481565b3480156105c957600080fd5b506001546104cb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156105f657600080fd5b506104cb6106053660046141e9565b612648565b34801561061657600080fd5b50604051600181526020016102bb565b34801561063257600080fd5b506102b1610641366004614198565b612695565b6106596106543660046144a2565b6127b6565b6040516102bb9190614517565b34801561067257600080fd5b506102b16106813660046143ab565b612928565b61028f6106943660046145a6565b612a55565b3480156106a557600080fd5b506106de6106b43660046141e9565b60076020526000908152604090205460ff81169061010090046bffffffffffffffffffffffff1682565b6040805192151583526bffffffffffffffffffffffff9091166020830152016102bb565b34801561070e57600080fd5b506104cb7f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c81565b34801561074257600080fd5b506104cb6107513660046141e9565b612b07565b34801561076257600080fd5b506002546104cb9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561078f57600080fd5b506102b161079e36600461428f565b612b86565b3480156107af57600080fd5b506102b16107be36600461428f565b600660209081526000928352604080842090915290825290205481565b61028f6107e93660046145a6565b612e4d565b60015473ffffffffffffffffffffffffffffffffffffffff163314610874576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b81156109995773ffffffffffffffffffffffffffffffffffffffff831615158061089b5750805b610901576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f776e61626c653a207a65726f20616464726573730000000000000000000000604482015260640161086b565b60015460405173ffffffffffffffffffffffffffffffffffffffff8086169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36001805473ffffffffffffffffffffffffffffffffffffffff85167fffffffffffffffffffffffff000000000000000000000000000000000000000091821617909155600280549091169055505050565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85161790555b505050565b60008054600114610a4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b60026000908155829003610a6257506000610aeb565b6000610a6d85610f64565b9050829150610a7e85858584612f00565b610a8c8686858460006131be565b6040805173ffffffffffffffffffffffffffffffffffffffff8781168252602082018490529295508288169289169133917fe72addf3d569f214b2c7d8c3ed740eb14bede9fa35d84b31d2c6fa3915ba866591015b60405180910390a4505b6001600055949350505050565b60608173ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b45573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610b8b9190810190614631565b604051602001610b9b91906146f1565b6040516020818303038152906040529050919050565b60008054600114610c1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b60026000556000610c2e83610f64565b9050610c3a8382613291565b91508115610e1e57610c4d83838361344d565b91506000807f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c73ffffffffffffffffffffffffffffffffffffffff1663aec0b5436040518163ffffffff1660e01b81526004016040805180830381865afa158015610cbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ce0919061475d565b915091506000610cef86610e2a565b905060ff831615610d645760006103e8610d0c60ff8616886147bb565b610d169190614827565b9050818111610d255780610d27565b815b958690039590508015610d6257610d5573ffffffffffffffffffffffffffffffffffffffff8816848361346d565b610d5f8183614862565b91505b505b808511610d715784610d73565b805b94508415610d9c57610d9c73ffffffffffffffffffffffffffffffffffffffff8716888761346d565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f3b3f8d7160df6e82375eae838252bcfb9dbd1f35d4c9aa96612b95b9147b702388604051610e1291815260200190565b60405180910390a45050505b50600160005592915050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610e97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebb9190614879565b92915050565b60608173ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f0e573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610f549190810190614631565b604051602001610b9b9190614892565b6000808290508073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd991906148fe565b610fe79060ff16601b614862565b610ff290600a614a3b565b8173ffffffffffffffffffffffffffffffffffffffff166399530b066040518163ffffffff1660e01b8152600401602060405180830381865afa15801561103d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110619190614879565b61106b91906147bb565b9392505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146110f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161086b565b73ffffffffffffffffffffffffffffffffffffffff821660009081526007602052604090205460ff1615611153576040517ff879800500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61115f601b600a614a3b565b816bffffffffffffffffffffffff1611156111a6576040517f01868fb800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006111b183611b8d565b90508073ffffffffffffffffffffffffffffffffffffffff163b600003611204576040517fc961953600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604080518082018252600181526bffffffffffffffffffffffff928316602080830191825273ffffffffffffffffffffffffffffffffffffffff9590951660009081526007909552919093209251835491517fffffffffffffffffffffffffffffffffffffff000000000000000000000000009092169015157fffffffffffffffffffffffffffffffffffffff000000000000000000000000ff16176101009190921602179055565b6000610ebb826112bd84612b07565b6112c685610f64565b61352c565b60015473ffffffffffffffffffffffffffffffffffffffff16331461134c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161086b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205460ff166113ab576040517f33a1e60000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff16600090815260076020526040902080547fffffffffffffffffffffffffffffffffffffff00000000000000000000000000169055565b60025473ffffffffffffffffffffffffffffffffffffffff16338114611479576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e6572604482015260640161086b565b60015460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36001805473ffffffffffffffffffffffffffffffffffffffff9092167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316179055600280549091169055565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260076020908152604080832081518083019092525460ff811615158083526101009091046bffffffffffffffffffffffff16928201929092529061159a576040517f33a1e60000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115a587612b07565b905060006115b288610f64565b90506115c08883338461367b565b73ffffffffffffffffffffffffffffffffffffffff8716611666576040517fb132d08f0000000000000000000000000000000000000000000000000000000081523360048201526024810187905273ffffffffffffffffffffffffffffffffffffffff83169063b132d08f90604401600060405180830381600087803b15801561164957600080fd5b505af115801561165d573d6000803e3d6000fd5b5050505061178b565b6040517fb460af940000000000000000000000000000000000000000000000000000000081526004810187905230602482015233604482015273ffffffffffffffffffffffffffffffffffffffff88169063b460af94906064016020604051808303816000875af11580156116df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117039190614879565b506040517fb132d08f0000000000000000000000000000000000000000000000000000000081523060048201526024810187905273ffffffffffffffffffffffffffffffffffffffff83169063b132d08f90604401600060405180830381600087803b15801561177257600080fd5b505af1158015611786573d6000803e3d6000fd5b505050505b6117b58684602001516bffffffffffffffffffffffff16601b600a6117b09190614a3b565b6137e5565b93506117c58589868460006131be565b98975050505050505050565b8215611a3d5760003373ffffffffffffffffffffffffffffffffffffffff1663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611824573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118489190614a47565b9050600061185582612b07565b90503373ffffffffffffffffffffffffffffffffffffffff8216146118a6576040517fc7b3d54400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118b183610f64565b905060006118c084848461352c565b73ffffffffffffffffffffffffffffffffffffffff80861660009081526004602090815260408083208590556003825280832087905560058252808320938e168352929052205490915061191a9085908b9084908a6138b5565b611925906001614a64565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152600660209081526040808320938e1683529290522055611963816001614a64565b73ffffffffffffffffffffffffffffffffffffffff85811660009081526005602090815260408083208e8516845290915280822093909355908a168152205480156119f4576119b5858a84848a6138b5565b6119c0906001614a64565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152600660209081526040808320938e16835292905220555b6119ff826001614a64565b73ffffffffffffffffffffffffffffffffffffffff9586166000908152600560209081526040808320988d1683529790529590952094909455505050505b5050505050565b60008054600114611ab1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b60026000908155829003611ac757506000611b7f565b5080611adf8686868685611ada83610f64565b613973565b6000611aea85612648565b9050611b0e73ffffffffffffffffffffffffffffffffffffffff8216333086613ceb565b611b19818487613daa565b6040805133815273ffffffffffffffffffffffffffffffffffffffff86811660208301529181018590528187169188811691908a16907fae17f80dea4c8f41253038dd6fd685a04fdc013157a7f9feb316de8d4fb88220906060015b60405180910390a4505b600160005595945050505050565b6040517f1a3df32e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82811660248301526000917f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c90911690631a3df32e906044015b602060405180830381865afa158015611c25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ebb9190614a47565b60608173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611c96573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611cdc9190810190614631565b604051602001610b9b9190614a7c565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260076020908152604080832081518083019092525460ff811615158083526101009091046bffffffffffffffffffffffff169282019290925290611d78576040517f33a1e60000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611d8386612b07565b90506000611d9087610f64565b9050611d9e8783338461367b565b6000611da988611b8d565b6040517fb132d08f0000000000000000000000000000000000000000000000000000000081523360048201526024810189905290915073ffffffffffffffffffffffffffffffffffffffff82169063b132d08f90604401600060405180830381600087803b158015611e1a57600080fd5b505af1158015611e2e573d6000803e3d6000fd5b50505050611e6d8785602001516bffffffffffffffffffffffff16601b600a611e579190614a3b565b611e619190614862565b6117b0601b600a614a3b565b94506117c58689878560006131be565b60608173ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611eca573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611f109190810190614631565b604051602001610b9b9190614ae8565b600080611f2c84612b07565b73ffffffffffffffffffffffffffffffffffffffff8086166000908152600560209081526040808320938816835292905290812054919250819003611f7657600092505050610ebb565b6120228585611f8988866112c68b610f64565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff89811660048301528691908816906370a08231906024015b602060405180830381865afa158015611ff9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061201d9190614879565b6138b5565b925060007f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c73ffffffffffffffffffffffffffffffffffffffff1663aec0b5436040518163ffffffff1660e01b81526004016040805180830381865afa158015612090573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120b4919061475d565b50905060ff8116156120e25760006103e86120d260ff8416876147bb565b6120dc9190614827565b90940393505b50505092915050565b60008054600114612158576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b6002600090815561216884610f64565b90506121748482613291565b9150811561263a576000807f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c73ffffffffffffffffffffffffffffffffffffffff1663aec0b5436040518163ffffffff1660e01b81526004016040805180830381865afa1580156121e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220d919061475d565b915091508160ff166000146123165760006103e861222e60ff8516876147bb565b6122389190614827565b9485900394905061224a87828661344d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290915060009073ffffffffffffffffffffffffffffffffffffffff8916906370a0823190602401602060405180830381865afa1580156122ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122de9190614879565b9050808211156122ec578091505b81156123135761231373ffffffffffffffffffffffffffffffffffffffff8916848461346d565b50505b600061232187611b8d565b9050600061232e88612b07565b905073ffffffffffffffffffffffffffffffffffffffff87166123795773ffffffffffffffffffffffffffffffffffffffff891633146123745761237488828b8861367b565b612385565b6123858882898861367b565b6040517f4047176800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8b8116600483015260248201889052831690634047176890604401600060405180830381600087803b1580156123f557600080fd5b505af1158015612409573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff881690506124b6576040517f4047176800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a8116600483015260248201889052821690634047176890604401600060405180830381600087803b15801561249957600080fd5b505af11580156124ad573d6000803e3d6000fd5b505050506125d2565b6040517f4047176800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260248201889052821690634047176890604401600060405180830381600087803b15801561252657600080fd5b505af115801561253a573d6000803e3d6000fd5b50506040517f01681a6200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8c811660048301528a1692506301681a6291506024016020604051808303816000875af11580156125ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d09190614879565b505b6040805133815273ffffffffffffffffffffffffffffffffffffffff8981166020830152918101889052818a16918b811691908d16907faa0217f7f8eadeb4cfdaf15b16299ea3c2669e542beb21cba5594d0711bdb0d09060600160405180910390a4505050505b506001600055949350505050565b60008173ffffffffffffffffffffffffffffffffffffffff1663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c25573d6000803e3d6000fd5b60008054600114612702576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b6002600090815582900361271857506000610aeb565b600061272385610f64565b9050612730858483613fd7565b915061273e85858484612f00565b61275f73ffffffffffffffffffffffffffffffffffffffff8616878561346d565b6040805173ffffffffffffffffffffffffffffffffffffffff868116825260208201869052808816929089169133917f49bc875ae5f8ca98bf14e67f59af932dd4e7ddf244b21c2e54c9d9db9fccd5fe9101610ae1565b60608167ffffffffffffffff8111156127d1576127d1614602565b60405190808252806020026020018201604052801561280457816020015b60608152602001906001900390816127ef5790505b50905060005b82811015612921576000803086868581811061282857612828614b54565b905060200281019061283a9190614b83565b604051612848929190614bef565b600060405180830381855af49150503d8060008114612883576040519150601f19603f3d011682016040523d82523d6000602084013e612888565b606091505b5091509150816128ee576044815110156128a157600080fd5b600481019050808060200190518101906128bb9190614631565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086b919061427c565b8084848151811061290157612901614b54565b60200260200101819052505050808061291990614bff565b91505061280a565b5092915050565b60008054600114612995576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b600260009081558290036129ab57506000611b7f565b60006129b685610f64565b90506129c3858483613fef565b91506129d3878787878686613973565b6129f573ffffffffffffffffffffffffffffffffffffffff8616333086613ceb565b6040805133815273ffffffffffffffffffffffffffffffffffffffff86811660208301529181018590528187169188811691908a16907fe6e692ca4618948f6e5a3045c43ffab44431c1c78092c8714b5b148db340380d90606001611b75565b6040517fdd62ed3e000000000000000000000000000000000000000000000000000000008152336004820152306024820152859073ffffffffffffffffffffffffffffffffffffffff88169063dd62ed3e90604401602060405180830381865afa158015612ac7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aeb9190614879565b1015612aff57612aff868686868686612e4d565b505050505050565b6040517f782f2b7700000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff82811660248301526000917f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c9091169063782f2b7790604401611c08565b60008054600114612bf3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f5245454e5452414e435900000000000000000000000000000000000000000000604482015260640161086b565b60026000908155612c0383610f64565b9050612c0f8382613291565b91508115610e1e576000807f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c73ffffffffffffffffffffffffffffffffffffffff1663aec0b5436040518163ffffffff1660e01b81526004016040805180830381865afa158015612c84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ca8919061475d565b915091508160ff16600014612db15760006103e8612cc960ff8516876147bb565b612cd39190614827565b94859003949050612ce586828661344d565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290915060009073ffffffffffffffffffffffffffffffffffffffff8816906370a0823190602401602060405180830381865afa158015612d55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d799190614879565b905080821115612d87578091505b8115612dae57612dae73ffffffffffffffffffffffffffffffffffffffff8816848461346d565b50505b612dbf8686868660016131be565b93508473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fb6a1db50c9f4db0410568b93c1387b9490762ea21a00868a7790b6e0953d3ab787604051612e3791815260200190565b60405180910390a4505050600160005592915050565b6040517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018690526064810185905260ff8416608482015260a4810183905260c4810182905273ffffffffffffffffffffffffffffffffffffffff87169063d505accf9060e4015b600060405180830381600087803b158015612ee057600080fd5b505af1158015612ef4573d6000803e3d6000fd5b50505050505050505050565b6000612f0b85611b8d565b90506000612f1886612b07565b90508173ffffffffffffffffffffffffffffffffffffffff163b600003612f6b576040517fc961953600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612f9a868273ffffffffffffffffffffffffffffffffffffffff881615612f925730612f94565b335b8661367b565b6040517fb132d08f0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff83169063b132d08f90604401600060405180830381600087803b15801561300857600080fd5b505af115801561301c573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff861690506130c7576040517fb132d08f0000000000000000000000000000000000000000000000000000000081523360048201526024810185905273ffffffffffffffffffffffffffffffffffffffff82169063b132d08f90604401600060405180830381600087803b1580156130aa57600080fd5b505af11580156130be573d6000803e3d6000fd5b50505050612aff565b6040517fb460af940000000000000000000000000000000000000000000000000000000081526004810185905230602482015233604482015273ffffffffffffffffffffffffffffffffffffffff86169063b460af94906064016020604051808303816000875af1158015613140573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131649190614879565b506040517fb132d08f0000000000000000000000000000000000000000000000000000000081523060048201526024810185905273ffffffffffffffffffffffffffffffffffffffff82169063b132d08f90604401612ec6565b6000806131cc86868661344d565b905082156131ef5760006131df87610e2a565b9050808211156131ed578091505b505b6040517ef714ce0000000000000000000000000000000000000000000000000000000081526004810182905273ffffffffffffffffffffffffffffffffffffffff888116602483015287169062f714ce906044016020604051808303816000875af1158015613262573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132869190614879565b979650505050505050565b60008061329d84612b07565b90508073ffffffffffffffffffffffffffffffffffffffff163b6000036132f0576040517fc961953600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006132fd85838661352c565b73ffffffffffffffffffffffffffffffffffffffff861660009081526005602090815260408083203384529091529020549091508015613399576040517f70a082310000000000000000000000000000000000000000000000000000000081523360048201819052613396918891908590859073ffffffffffffffffffffffffffffffffffffffff8916906370a0823190602401611fdc565b93505b73ffffffffffffffffffffffffffffffffffffffff86166000908152600460209081526040808320859055600390915290208590556133d9826001614a64565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260056020908152604080832033845290915290205583156120e25773ffffffffffffffffffffffffffffffffffffffff8616600090815260066020908152604080832033845290915290206001905550505092915050565b60006134658361345f601b600a614a3b565b846137e5565b949350505050565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080613526576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c45440000000000000000000000000000000000604482015260640161086b565b50505050565b6000808373ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561357a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061359e9190614879565b9050806000036135d557505073ffffffffffffffffffffffffffffffffffffffff831660009081526004602052604090205461106b565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260409020548084116136305750505073ffffffffffffffffffffffffffffffffffffffff831660009081526004602052604090205461106b565b600061364782860361364189610e2a565b856137e5565b73ffffffffffffffffffffffffffffffffffffffff8816600090815260046020526040902054909150613286908290614a64565b600061368885858461352c565b73ffffffffffffffffffffffffffffffffffffffff8087166000908152600560209081526040808320938816835292905220549091508015613764576040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8086166004830152613725918891879186918691908b16906370a0823190602401611fdc565b613730906001614a64565b73ffffffffffffffffffffffffffffffffffffffff8088166000908152600660209081526040808320938916835292905220555b73ffffffffffffffffffffffffffffffffffffffff86166000908152600460209081526040808320859055600390915290208390556137a4826001614a64565b73ffffffffffffffffffffffffffffffffffffffff968716600090815260056020908152604080832097909916825295909552959093209490945550505050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060000361383c576000841161383157600080fd5b50829004905061106b565b80841161384857600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8301613902838287116138ec5760006138f0565b8287035b6b033b2e3c9fd0803ce80000006137e5565b73ffffffffffffffffffffffffffffffffffffffff8089166000908152600660209081526040808320938b16835292905220549092506001811115613968579182017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01915b505095945050505050565b600061397e85611b8d565b90508073ffffffffffffffffffffffffffffffffffffffff163b600003613a59576040517fe31ce2f300000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff86811660248301527f000000000000000000000000bd16088611054fce04711aa9509d1d86e04dce2c169063e31ce2f39060440160408051808303816000875af1158015613a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a569190614c37565b50505b6000613a6486612b07565b9050613a94868273ffffffffffffffffffffffffffffffffffffffff881615613a8d5787612f94565b898661367b565b6040517f4047176800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015260248201869052831690634047176890604401600060405180830381600087803b158015613b0457600080fd5b505af1158015613b18573d6000803e3d6000fd5b50505073ffffffffffffffffffffffffffffffffffffffff86169050613bc5576040517f4047176800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015260248201869052821690634047176890604401600060405180830381600087803b158015613ba857600080fd5b505af1158015613bbc573d6000803e3d6000fd5b50505050613ce1565b6040517f4047176800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff868116600483015260248201869052821690634047176890604401600060405180830381600087803b158015613c3557600080fd5b505af1158015613c49573d6000803e3d6000fd5b50506040517f01681a6200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8a81166004830152881692506301681a6291506024016020604051808303816000875af1158015613cbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cdf9190614879565b505b5050505050505050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080611a3d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640161086b565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff828116602483015284169063dd62ed3e90604401602060405180830381865afa158015613e1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e409190614879565b15613e6757613e6773ffffffffffffffffffffffffffffffffffffffff8416826000614002565b613e8873ffffffffffffffffffffffffffffffffffffffff84168284614002565b6040517fb6b55f250000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82169063b6b55f25906024016020604051808303816000875af1158015613ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613f199190614879565b506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff828116602483015284169063dd62ed3e90604401602060405180830381865afa158015613f8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fb09190614879565b156109da576109da73ffffffffffffffffffffffffffffffffffffffff8416826000614002565b60006134658383613fea601b600a614a3b565b6140bb565b600061346583836117b0601b600a614a3b565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080613526576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c4544000000000000000000000000000000000000604482015260640161086b565b60006140c88484846137e5565b9050600082806140da576140da6147f8565b848609111561106b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811061410f57600080fd5b6001019392505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461413b57600080fd5b50565b8035801515811461414e57600080fd5b919050565b60008060006060848603121561416857600080fd5b833561417381614119565b92506141816020850161413e565b915061418f6040850161413e565b90509250925092565b600080600080608085870312156141ae57600080fd5b84356141b981614119565b935060208501356141c981614119565b925060408501356141d981614119565b9396929550929360600135925050565b6000602082840312156141fb57600080fd5b813561106b81614119565b60005b83811015614221578181015183820152602001614209565b838111156135265750506000910152565b6000815180845261424a816020860160208601614206565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061106b6020830184614232565b600080604083850312156142a257600080fd5b82356142ad81614119565b915060208301356142bd81614119565b809150509250929050565b600080604083850312156142db57600080fd5b82356142e681614119565b915060208301356bffffffffffffffffffffffff811681146142bd57600080fd5b6000806000806080858703121561431d57600080fd5b843561432881614119565b9350602085013561433881614119565b925060408501359150606085013561434f81614119565b939692955090935050565b600080600080600060a0868803121561437257600080fd5b853561437d81614119565b9450602086013561438d81614119565b94979496505050506040830135926060810135926080909101359150565b600080600080600060a086880312156143c357600080fd5b85356143ce81614119565b945060208601356143de81614119565b935060408601356143ee81614119565b925060608601356143fe81614119565b949793965091946080013592915050565b60008060006060848603121561442457600080fd5b833561442f81614119565b925060208401359150604084013561444681614119565b809150509250925092565b6000806000806080858703121561446757600080fd5b843561447281614119565b9350602085013561448281614119565b9250604085013561449281614119565b9150606085013561434f81614119565b600080602083850312156144b557600080fd5b823567ffffffffffffffff808211156144cd57600080fd5b818501915085601f8301126144e157600080fd5b8135818111156144f057600080fd5b8660208260051b850101111561450557600080fd5b60209290920196919550909350505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b8281101561458a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452614578858351614232565b9450928501929085019060010161453e565b5092979650505050505050565b60ff8116811461413b57600080fd5b60008060008060008060c087890312156145bf57600080fd5b86356145ca81614119565b9550602087013594506040870135935060608701356145e881614597565b9598949750929560808101359460a0909101359350915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561464357600080fd5b815167ffffffffffffffff8082111561465b57600080fd5b818401915084601f83011261466f57600080fd5b81518181111561468157614681614602565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156146c7576146c7614602565b816040528281528760208487010111156146e057600080fd5b613286836020830160208801614206565b7f54696d656c657373200000000000000000000000000000000000000000000000815260008251614729816009850160208701614206565b7f2050657270657475616c205969656c6420546f6b656e000000000000000000006009939091019283015250601f01919050565b6000806040838503121561477057600080fd5b825161477b81614597565b60208401519092506142bd81614119565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156147f3576147f361478c565b500290565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261485d577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000828210156148745761487461478c565b500390565b60006020828403121561488b57600080fd5b5051919050565b7f54696d656c6573732000000000000000000000000000000000000000000000008152600082516148ca816009850160208701614206565b7f204e65676174697665205969656c6420546f6b656e00000000000000000000006009939091019283015250601e01919050565b60006020828403121561491057600080fd5b815161106b81614597565b600181815b8085111561497457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561495a5761495a61478c565b8085161561496757918102915b93841c9390800290614920565b509250929050565b60008261498b57506001610ebb565b8161499857506000610ebb565b81600181146149ae57600281146149b8576149d4565b6001915050610ebb565b60ff8411156149c9576149c961478c565b50506001821b610ebb565b5060208310610133831016604e8410600b84101617156149f7575081810a610ebb565b614a01838361491b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115614a3357614a3361478c565b029392505050565b600061106b838361497c565b600060208284031215614a5957600080fd5b815161106b81614119565b60008219821115614a7757614a7761478c565b500190565b7fe2889e2d00000000000000000000000000000000000000000000000000000000815260008251614ab4816004850160208701614206565b7f2d505954000000000000000000000000000000000000000000000000000000006004939091019283015250600801919050565b7fe2889e2d00000000000000000000000000000000000000000000000000000000815260008251614b20816004850160208701614206565b7f2d4e5954000000000000000000000000000000000000000000000000000000006004939091019283015250600801919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112614bb857600080fd5b83018035915067ffffffffffffffff821115614bd357600080fd5b602001915036819003821315614be857600080fd5b9250929050565b8183823760009101908152919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c3057614c3061478c565b5060010190565b60008060408385031215614c4a57600080fd5b825161477b8161411956fea2646970667358221220f57a945c7a0ad4dac42f63065215c87892517bbce8d4e19d727de715f1ff9de064736f6c634300080d0033

Verified Source Code Partial Match

Compiler: v0.8.13+commit.abaa5c0e EVM: london Optimization: Yes (1000000 runs)
YearnGate.sol 2993 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.13;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    event Debug(bool one, bool two, uint256 retsize);

    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
            mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol
// Simplified by BoringCrypto

contract BoringOwnableData {
    address public owner;
    address public pendingOwner;
}

contract BoringOwnable is BoringOwnableData {
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @notice `owner` defaults to msg.sender on construction.
    constructor() {
        owner = msg.sender;
        emit OwnershipTransferred(address(0), msg.sender);
    }

    /// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
    /// Can only be invoked by the current `owner`.
    /// @param newOwner Address of the new owner.
    /// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
    /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
    function transferOwnership(
        address newOwner,
        bool direct,
        bool renounce
    ) public onlyOwner {
        if (direct) {
            // Checks
            require(newOwner != address(0) || renounce, "Ownable: zero address");

            // Effects
            emit OwnershipTransferred(owner, newOwner);
            owner = newOwner;
            pendingOwner = address(0);
        } else {
            // Effects
            pendingOwner = newOwner;
        }
    }

    /// @notice Needs to be called by `pendingOwner` to claim ownership.
    function claimOwnership() public {
        address _pendingOwner = pendingOwner;

        // Checks
        require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");

        // Effects
        emit OwnershipTransferred(owner, _pendingOwner);
        owner = _pendingOwner;
        pendingOwner = address(0);
    }

    /// @notice Only allows the `owner` to execute the function.
    modifier onlyOwner() {
        require(msg.sender == owner, "Ownable: caller is not the owner");
        _;
    }
}

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // Divide z by the denominator.
            z := div(z, denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        assembly {
            // Store x * y in z for now.
            z := mul(x, y)

            // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
            if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
                revert(0, 0)
            }

            // First, divide z - 1 by the denominator and add 1.
            // We allow z - 1 to underflow if z is 0, because we multiply the
            // end result by 0 if z is zero, ensuring we return 0 if z is zero.
            z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        assembly {
            // Start off with z at 1.
            z := 1

            // Used below to help find a nearby power of 2.
            let y := x

            // Find the lowest power of 2 that is at least sqrt(x).
            if iszero(lt(y, 0x100000000000000000000000000000000)) {
                y := shr(128, y) // Like dividing by 2 ** 128.
                z := shl(64, z) // Like multiplying by 2 ** 64.
            }
            if iszero(lt(y, 0x10000000000000000)) {
                y := shr(64, y) // Like dividing by 2 ** 64.
                z := shl(32, z) // Like multiplying by 2 ** 32.
            }
            if iszero(lt(y, 0x100000000)) {
                y := shr(32, y) // Like dividing by 2 ** 32.
                z := shl(16, z) // Like multiplying by 2 ** 16.
            }
            if iszero(lt(y, 0x10000)) {
                y := shr(16, y) // Like dividing by 2 ** 16.
                z := shl(8, z) // Like multiplying by 2 ** 8.
            }
            if iszero(lt(y, 0x100)) {
                y := shr(8, y) // Like dividing by 2 ** 8.
                z := shl(4, z) // Like multiplying by 2 ** 4.
            }
            if iszero(lt(y, 0x10)) {
                y := shr(4, y) // Like dividing by 2 ** 4.
                z := shl(2, z) // Like multiplying by 2 ** 2.
            }
            if iszero(lt(y, 0x8)) {
                // Equivalent to 2 ** z.
                z := shl(1, z)
            }

            // Shifting right by 1 is like dividing by 2.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // Compute a rounded down version of z.
            let zRoundDown := div(x, z)

            // If zRoundDown is smaller, use it.
            if lt(zRoundDown, z) {
                z := zRoundDown
            }
        }
    }
}

/// @notice Minimal ERC4626 tokenized Vault implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/mixins/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    ERC20 public immutable asset;

    constructor(
        ERC20 _asset,
        string memory _name,
        string memory _symbol
    ) ERC20(_name, _symbol, _asset.decimals()) {
        asset = _asset;
    }

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
        // Check for rounding error since we round down in previewDeposit.
        require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
        assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.

        // Need to transfer before minting or ERC777s could reenter.
        asset.safeTransferFrom(msg.sender, address(this), assets);

        _mint(receiver, shares);

        emit Deposit(msg.sender, receiver, assets, shares);

        afterDeposit(assets, shares);
    }

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public virtual returns (uint256 shares) {
        shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.

        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public virtual returns (uint256 assets) {
        if (msg.sender != owner) {
            uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.

            if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
        }

        // Check for rounding error since we round down in previewRedeem.
        require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");

        beforeWithdraw(assets, shares);

        _burn(owner, shares);

        emit Withdraw(msg.sender, receiver, owner, assets, shares);

        asset.safeTransfer(receiver, assets);
    }

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function previewDeposit(uint256 assets) public view virtual returns (uint256) {
        return convertToShares(assets);
    }

    function previewMint(uint256 shares) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
    }

    function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
    }

    function previewRedeem(uint256 shares) public view virtual returns (uint256) {
        return convertToAssets(shares);
    }

    /*//////////////////////////////////////////////////////////////
                     DEPOSIT/WITHDRAWAL LIMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    function maxDeposit(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxMint(address) public view virtual returns (uint256) {
        return type(uint256).max;
    }

    function maxWithdraw(address owner) public view virtual returns (uint256) {
        return convertToAssets(balanceOf[owner]);
    }

    function maxRedeem(address owner) public view virtual returns (uint256) {
        return balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HOOKS LOGIC
    //////////////////////////////////////////////////////////////*/

    function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}

    function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}

/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
    uint256 private locked = 1;

    modifier nonReentrant() virtual {
        require(locked == 1, "REENTRANCY");

        locked = 2;

        _;

        locked = 1;
    }
}

/// @notice Library for converting between addresses and bytes32 values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/Bytes32AddressLib.sol)
library Bytes32AddressLib {
    function fromLast20Bytes(bytes32 bytesValue) internal pure returns (address) {
        return address(uint160(uint256(bytesValue)));
    }

    function fillLast12Bytes(address addressValue) internal pure returns (bytes32) {
        return bytes32(bytes20(addressValue));
    }
}

/// @title BaseERC20
/// @author zefram.eth
/// @notice The base ERC20 contract used by NegativeYieldToken and PerpetualYieldToken
/// @dev Uses the same number of decimals as the vault's underlying token
contract BaseERC20 is ERC20 {
    /// -----------------------------------------------------------------------
    /// Errors
    /// -----------------------------------------------------------------------

    error Error_NotGate();

    /// -----------------------------------------------------------------------
    /// Immutable parameters
    /// -----------------------------------------------------------------------

    Gate public immutable gate;
    address public immutable vault;

    /// -----------------------------------------------------------------------
    /// Constructor
    /// -----------------------------------------------------------------------

    constructor(
        string memory name_,
        string memory symbol_,
        Gate gate_,
        address vault_
    ) ERC20(name_, symbol_, gate_.getUnderlyingOfVault(vault_).decimals()) {
        gate = gate_;
        vault = vault_;
    }

    /// -----------------------------------------------------------------------
    /// Gate-callable functions
    /// -----------------------------------------------------------------------

    function gateMint(address to, uint256 amount) external virtual {
        if (msg.sender != address(gate)) {
            revert Error_NotGate();
        }

        _mint(to, amount);
    }

    function gateBurn(address from, uint256 amount) external virtual {
        if (msg.sender != address(gate)) {
            revert Error_NotGate();
        }

        _burn(from, amount);
    }
}

/// @title NegativeYieldToken
/// @author zefram.eth
/// @notice The ERC20 contract representing negative yield tokens
contract NegativeYieldToken is BaseERC20 {
    /// -----------------------------------------------------------------------
    /// Constructor
    /// -----------------------------------------------------------------------

    constructor(Gate gate_, address vault_)
        BaseERC20(
            gate_.negativeYieldTokenName(vault_),
            gate_.negativeYieldTokenSymbol(vault_),
            gate_,
            vault_
        )
    {}
}

/// @title PerpetualYieldToken
/// @author zefram.eth
/// @notice The ERC20 contract representing perpetual yield tokens
contract PerpetualYieldToken is BaseERC20 {
    /// -----------------------------------------------------------------------
    /// Constructor
    /// -----------------------------------------------------------------------

    constructor(Gate gate_, address vault_)
        BaseERC20(
            gate_.perpetualYieldTokenName(vault_),
            gate_.perpetualYieldTokenSymbol(vault_),
            gate_,
            vault_
        )
    {}

    /// -----------------------------------------------------------------------
    /// ERC20 overrides
    /// -----------------------------------------------------------------------

    function transfer(address to, uint256 amount)
        public
        virtual
        override
        returns (bool)
    {
        // load balances to save gas
        uint256 fromBalance = balanceOf[msg.sender];
        uint256 toBalance = balanceOf[to];

        // call transfer hook
        gate.beforePerpetualYieldTokenTransfer(
            msg.sender,
            to,
            amount,
            fromBalance,
            toBalance
        );

        // do transfer
        // skip during self transfers since toBalance is cached
        // which leads to free minting, a critical issue
        if (msg.sender != to) {
            balanceOf[msg.sender] = fromBalance - amount;

            // Cannot overflow because the sum of all user
            // balances can't exceed the max uint256 value.
            unchecked {
                balanceOf[to] = toBalance + amount;
            }
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        // load balances to save gas
        uint256 fromBalance = balanceOf[from];
        uint256 toBalance = balanceOf[to];

        // call transfer hook
        gate.beforePerpetualYieldTokenTransfer(
            from,
            to,
            amount,
            fromBalance,
            toBalance
        );

        // update allowance
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max)
            allowance[from][msg.sender] = allowed - amount;

        // do transfer
        // skip during self transfers since toBalance is cached
        // which leads to free minting, a critical issue
        if (from != to) {
            balanceOf[from] = fromBalance - amount;

            // Cannot overflow because the sum of all user
            // balances can't exceed the max uint256 value.
            unchecked {
                balanceOf[to] = toBalance + amount;
            }
        }

        emit Transfer(from, to, amount);

        return true;
    }
}

contract Factory is BoringOwnable {
    /// -----------------------------------------------------------------------
    /// Library usage
    /// -----------------------------------------------------------------------

    using Bytes32AddressLib for address;
    using Bytes32AddressLib for bytes32;

    /// -----------------------------------------------------------------------
    /// Errors
    /// -----------------------------------------------------------------------

    error Error_ProtocolFeeRecipientIsZero();

    /// -----------------------------------------------------------------------
    /// Events
    /// -----------------------------------------------------------------------

    event SetProtocolFee(ProtocolFeeInfo protocolFeeInfo_);
    event DeployYieldTokenPair(
        Gate indexed gate,
        address indexed vault,
        NegativeYieldToken nyt,
        PerpetualYieldToken pyt
    );

    /// -----------------------------------------------------------------------
    /// Storage variables
    /// -----------------------------------------------------------------------

    struct ProtocolFeeInfo {
        uint8 fee; // each increment represents 0.1%, so max is 25.5%
        address recipient;
    }
    /// @notice The protocol fee and the fee recipient address.
    ProtocolFeeInfo public protocolFeeInfo;

    /// -----------------------------------------------------------------------
    /// Constructor
    /// -----------------------------------------------------------------------

    constructor(ProtocolFeeInfo memory protocolFeeInfo_) {
        if (
            protocolFeeInfo_.fee != 0 &&
            protocolFeeInfo_.recipient == address(0)
        ) {
            revert Error_ProtocolFeeRecipientIsZero();
        }
        protocolFeeInfo = protocolFeeInfo_;
        emit SetProtocolFee(protocolFeeInfo_);
    }

    /// -----------------------------------------------------------------------
    /// User actions
    /// -----------------------------------------------------------------------

    /// @notice Deploys the NegativeYieldToken and PerpetualYieldToken associated with a vault.
    /// @dev Will revert if they have already been deployed.
    /// @param gate The gate that will use the NYT and PYT
    /// @param vault The vault to deploy NYT and PYT for
    /// @return nyt The deployed NegativeYieldToken
    /// @return pyt The deployed PerpetualYieldToken
    function deployYieldTokenPair(Gate gate, address vault)
        public
        virtual
        returns (NegativeYieldToken nyt, PerpetualYieldToken pyt)
    {
        // Use the CREATE2 opcode to deploy new NegativeYieldToken and PerpetualYieldToken contracts.
        // This will revert if the contracts have already been deployed,
        // as the salt & bytecode hash would be the same and we can't deploy with it twice.
        nyt = new NegativeYieldToken{salt: bytes32(0)}(gate, vault);
        pyt = new PerpetualYieldToken{salt: bytes32(0)}(gate, vault);

        emit DeployYieldTokenPair(gate, vault, nyt, pyt);
    }

    /// -----------------------------------------------------------------------
    /// Getters
    /// -----------------------------------------------------------------------

    /// @notice Returns the NegativeYieldToken associated with a gate & vault pair.
    /// @dev Returns non-zero value even if the contract hasn't been deployed yet.
    /// @param gate The gate to query
    /// @param vault The vault to query
    /// @return The NegativeYieldToken address
    function getNegativeYieldToken(Gate gate, address vault)
        public
        view
        virtual
        returns (NegativeYieldToken)
    {
        return
            NegativeYieldToken(_computeYieldTokenAddress(gate, vault, false));
    }

    /// @notice Returns the PerpetualYieldToken associated with a gate & vault pair.
    /// @dev Returns non-zero value even if the contract hasn't been deployed yet.
    /// @param gate The gate to query
    /// @param vault The vault to query
    /// @return The PerpetualYieldToken address
    function getPerpetualYieldToken(Gate gate, address vault)
        public
        view
        virtual
        returns (PerpetualYieldToken)
    {
        return
            PerpetualYieldToken(_computeYieldTokenAddress(gate, vault, true));
    }

    /// -----------------------------------------------------------------------
    /// Owner functions
    /// -----------------------------------------------------------------------

    /// @notice Updates the protocol fee and/or the protocol fee recipient.
    /// Only callable by the owner.
    /// @param protocolFeeInfo_ The new protocol fee info
    function ownerSetProtocolFee(ProtocolFeeInfo calldata protocolFeeInfo_)
        external
        virtual
        onlyOwner
    {
        if (
            protocolFeeInfo_.fee != 0 &&
            protocolFeeInfo_.recipient == address(0)
        ) {
            revert Error_ProtocolFeeRecipientIsZero();
        }
        protocolFeeInfo = protocolFeeInfo_;

        emit SetProtocolFee(protocolFeeInfo_);
    }

    /// -----------------------------------------------------------------------
    /// Internal utilities
    /// -----------------------------------------------------------------------

    /// @dev Computes the address of PYTs and NYTs using CREATE2.
    function _computeYieldTokenAddress(
        Gate gate,
        address vault,
        bool isPerpetualYieldToken
    ) internal view virtual returns (address) {
        return
            keccak256(
                abi.encodePacked(
                    // Prefix:
                    bytes1(0xFF),
                    // Creator:
                    address(this),
                    // Salt:
                    bytes32(0),
                    // Bytecode hash:
                    keccak256(
                        abi.encodePacked(
                            // Deployment bytecode:
                            isPerpetualYieldToken
                                ? type(PerpetualYieldToken).creationCode
                                : type(NegativeYieldToken).creationCode,
                            // Constructor arguments:
                            abi.encode(gate, vault)
                        )
                    )
                )
            ).fromLast20Bytes(); // Convert the CREATE2 hash into an address.
    }
}

abstract contract IxPYT is ERC4626 {
    function sweep(address receiver) external virtual returns (uint256 shares);
}

/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
    /// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
    function mulDiv(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = a * b
            // Compute the product mod 2**256 and mod 2**256 - 1
            // then use the Chinese Remainder Theorem to reconstruct
            // the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2**256 + prod0
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division
            if (prod1 == 0) {
                require(denominator > 0);
                assembly {
                    result := div(prod0, denominator)
                }
                return result;
            }

            // Make sure the result is less than 2**256.
            // Also prevents denominator == 0
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0]
            // Compute remainder using mulmod
            uint256 remainder;
            assembly {
                remainder := mulmod(a, b, denominator)
            }
            // Subtract 256 bit number from 512 bit number
            assembly {
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator
            // Compute largest power of two divisor of denominator.
            // Always >= 1.
            uint256 twos = (0 - denominator) & denominator;
            // Divide denominator by power of two
            assembly {
                denominator := div(denominator, twos)
            }

            // Divide [prod1 prod0] by the factors of two
            assembly {
                prod0 := div(prod0, twos)
            }
            // Shift in bits from prod1 into prod0. For this we need
            // to flip `twos` such that it is 2**256 / twos.
            // If twos is zero, then it becomes one
            assembly {
                twos := add(div(sub(0, twos), twos), 1)
            }
            prod0 |= prod1 * twos;

            // Invert denominator mod 2**256
            // Now that denominator is an odd number, it has an inverse
            // modulo 2**256 such that denominator * inv = 1 mod 2**256.
            // Compute the inverse by starting with a seed that is correct
            // correct for four bits. That is, denominator * inv = 1 mod 2**4
            uint256 inv = (3 * denominator) ^ 2;
            // Now use 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.
            inv *= 2 - denominator * inv; // inverse mod 2**8
            inv *= 2 - denominator * inv; // inverse mod 2**16
            inv *= 2 - denominator * inv; // inverse mod 2**32
            inv *= 2 - denominator * inv; // inverse mod 2**64
            inv *= 2 - denominator * inv; // inverse mod 2**128
            inv *= 2 - denominator * inv; // inverse mod 2**256

            // 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**256. Since the precoditions guarantee
            // that the outcome is less than 2**256, this is the final result.
            // We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inv;
            return result;
        }
    }

    /// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
    /// @param a The multiplicand
    /// @param b The multiplier
    /// @param denominator The divisor
    /// @return result The 256-bit result
    function mulDivRoundingUp(
        uint256 a,
        uint256 b,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            result = mulDiv(a, b, denominator);
            if (mulmod(a, b, denominator) > 0) {
                require(result < type(uint256).max);
                result++;
            }
        }
    }
}

/// @title Multicall
/// @notice Enables calling multiple methods in a single call to the contract
abstract contract Multicall {
    function multicall(bytes[] calldata data)
        external
        payable
        returns (bytes[] memory results)
    {
        results = new bytes[](data.length);
        for (uint256 i = 0; i < data.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(
                data[i]
            );

            if (!success) {
                // Next 5 lines from https://ethereum.stackexchange.com/a/83577
                if (result.length < 68) revert();
                assembly {
                    result := add(result, 0x04)
                }
                revert(abi.decode(result, (string)));
            }

            results[i] = result;
        }
    }
}

/// @title Self Permit
/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route
/// @dev These functions are expected to be embedded in multicalls to allow EOAs to approve a contract and call a function
/// that requires an approval in a single transaction.
abstract contract SelfPermit {
    function selfPermit(
        ERC20 token,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public payable {
        token.permit(msg.sender, address(this), value, deadline, v, r, s);
    }

    function selfPermitIfNecessary(
        ERC20 token,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external payable {
        if (token.allowance(msg.sender, address(this)) < value)
            selfPermit(token, value, deadline, v, r, s);
    }
}

///...

// [truncated — 113657 bytes total]

Read Contract

computeYieldPerToken 0x43e002c4 → uint256
emergencyExitStatusOfVault 0xc38a23fd → bool, uint96
factory 0xc45a0155 → address
getClaimableYieldAmount 0x748b259c → uint256
getNegativeYieldTokenForVault 0x696bf4b7 → address
getPerpetualYieldTokenForVault 0xd42b860d → address
getPricePerVaultShare 0x2102d9e2 → uint256
getUnderlyingOfVault 0x927dd6bc → address
getVaultShareBalance 0x1e72063c → uint256
negativeYieldTokenName 0x1f27f927 → string
negativeYieldTokenSymbol 0x7134bf5c → string
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address
perpetualYieldTokenName 0x172693e7 → string
perpetualYieldTokenSymbol 0x69f6d9b3 → string
pricePerVaultShareStored 0x88d41b02 → uint256
userAccruedYield 0xe9592945 → uint256
userYieldPerTokenStored 0x41725efa → uint256
vaultSharesIsERC20 0x92e226a6 → bool
yieldPerTokenStored 0x4ba58cc1 → uint256

Write Contract 17 functions

These functions modify contract state and require a wallet transaction to execute.

beforePerpetualYieldTokenTransfer 0x5fb87d1c
address from
address to
uint256 amount
uint256 fromBalance
uint256 toBalance
claimOwnership 0x4e71e0c8
No parameters
claimYieldAndEnter 0x875efaae
address nytRecipient
address pytRecipient
address vault
address xPYT
returns: uint256
claimYieldInUnderlying 0xe6c893c0
address recipient
address vault
returns: uint256
claimYieldInVaultShares 0x1c7748b1
address recipient
address vault
returns: uint256
emergencyExitNegativeYieldToken 0x6ca98360
address vault
uint256 amount
address recipient
returns: uint256
emergencyExitPerpetualYieldToken 0x5cb258dd
address vault
address xPYT
uint256 amount
address recipient
returns: uint256
enterWithUnderlying 0x63f41f82
address nytRecipient
address pytRecipient
address vault
address xPYT
uint256 underlyingAmount
returns: uint256
enterWithVaultShares 0xae476607
address nytRecipient
address pytRecipient
address vault
address xPYT
uint256 vaultSharesAmount
returns: uint256
exitToUnderlying 0x095ca64c
address recipient
address vault
address xPYT
uint256 underlyingAmount
returns: uint256
exitToVaultShares 0xa5ca5c04
address recipient
address vault
address xPYT
uint256 vaultSharesAmount
returns: uint256
multicall 0xac9650d8
bytes[] data
returns: bytes[]
ownerActivateEmergencyExitForVault 0x220bd316
address vault
uint96 pytPriceInUnderlying
ownerDeactivateEmergencyExitForVault 0x46269502
address vault
selfPermit 0xf3995c67
address token
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
selfPermitIfNecessary 0xc2e3140a
address token
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
transferOwnership 0x078dfbe7
address newOwner
bool direct
bool renounce

Recent Transactions

No transactions found for this address