Address Contract Partially Verified
Address
0x2EDFb4eb6A7FB78B3aC9204F179510865D77C660
Balance
0 ETH
Nonce
1
Code Size
17276 bytes
Creator
0x3765A685...3a91 at tx 0x9ca4dc4b...70b608
Indexed Transactions
0 (1 on-chain, 1.6% indexed)
Contract Bytecode
17276 bytes
0x608060405234801561001057600080fd5b50600436106102a05760003560e01c80638bcd979711610167578063c350de6c116100ce578063d547741f11610087578063d547741f14610693578063d853015e146106a6578063dc49a07b146106bb578063e28178cc146106c3578063e6025393146106d4578063f493ca70146106fb57600080fd5b8063c350de6c14610621578063c431280e14610634578063c876a2a714610647578063cab46bc61461065a578063cea462131461066d578063cea9d26f1461068057600080fd5b8063a217fddf11610120578063a217fddf14610572578063a9c3ebda1461057a578063aa278b03146105ad578063aa443ac0146105c0578063ab16b58a146105d3578063b1c660f7146105fa57600080fd5b80638bcd9797146104df5780638fa468901461050657806391d1485414610521578063954c1c0d146105345780639b5c9261146105475780639b745aec1461055a57600080fd5b806340fb07a01161020b5780636400a4af116101c45780636400a4af146104455780637265580f1461046c57806378cf12b21461047f5780637ecebe001461048657806380bc659a146104a65780638a96e304146104b857600080fd5b806340fb07a0146103c25780634101d9f4146103ea578063430b09521461040f578063476cce03146104225780635921c8e01461042a578063605297e11461043d57600080fd5b8063236fc8ad1161025d578063236fc8ad14610338578063248a9ca31461034a5780632f2ff15d1461036d578063353f03bd146103805780633644e515146103a757806336568abe146103af57600080fd5b806301ffc9a7146102a557806310ce0516146102cd578063110934d6146102d557806316d8887a146102eb5780631f3da150146103125780631fde40bb14610323575b600080fd5b6102b86102b3366004613dab565b61070e565b60405190151581526020015b60405180910390f35b6102b8610745565b6102dd610771565b6040519081526020016102c4565b6102dd7f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1681565b6039546001600160801b03166102dd565b610336610331366004613df1565b6107c3565b005b603754600160a01b900460ff166102b8565b6102dd610358366004613e0c565b60009081526020819052604090206001015490565b61033661037b366004613e25565b6107e8565b6102dd7f6dac4cc0544e34aa1a4ed2862f6de78290e3f18f00fe77179ee8ef34de9dfa2481565b6102dd610812565b6103366103bd366004613e25565b61081c565b6103d56103d0366004613e25565b61089b565b604080519283526020830191909152016102c4565b6037546001600160a01b03165b6040516001600160a01b0390911681526020016102c4565b61033661041d366004613e68565b61090b565b6103d561092c565b6102dd610438366004613e0c565b6109cf565b6102dd610c63565b6102dd7ff570a3b94987b56be9e62084f59006353309fa95357dfbc6d3ea78cce6382d1381565b61033661047a366004613e83565b610e92565b60016102dd565b6102dd610494366004613df1565b60356020526000908152604090205481565b603754600160a81b900460ff166102b8565b6102dd7fcfb9ac928a9a202b47d70fc2e62c0dade955274336ca821ed60aeb2142af92e681565b6102dd7fbf63066482b01a20567880b14a2934fecb21c925e6bcc0a0a091c59723fa9c0681565b6038546040516001600160801b0390911681526020016102c4565b6102b861052f366004613e25565b610fd1565b6103d5610542366004613ec6565b610ffa565b6102dd610555366004613e0c565b611206565b603854600160801b90046001600160801b03166102dd565b6102dd600081565b61058d610588366004613e0c565b6114fd565b6040805194855260208501939093529183015260608201526080016102c4565b61058d6105bb366004613e0c565b611754565b6103d56105ce366004613e25565b611999565b6103f77f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b7281565b6103f77f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f81565b6102dd61062f366004613e0c565b6119fd565b61058d610642366004613e0c565b611eb4565b610336610655366004613df1565b611ed2565b610336610668366004613f7a565b611ef3565b61058d61067b366004613e0c565b612022565b61033661068e366004613f97565b612031565b6103366106a1366004613e25565b612318565b6102dd60008051602061432783398151915281565b61033661233d565b6036546001600160a01b03166103f7565b6103f77f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e81565b6103d5610709366004613ec6565b61234f565b60006001600160e01b03198216637965db0b60e01b148061073f57506301ffc9a760e01b6001600160e01b03198316145b92915050565b603754600090600160a01b900460ff1615801561076c5750603754600160a81b900460ff16155b905090565b6038546000906001600160801b03600160801b820481169116116107965760006107b5565b6038546107b5906001600160801b03600160801b820481169116613fe9565b6001600160801b0316905090565b6000805160206143278339815191526107db8161254b565b6107e482612558565b5050565b6000828152602081905260409020600101546108038161254b565b61080d83836125f9565b505050565b600061076c61267d565b6001600160a01b03811633146108915760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6107e482826127a4565b6037546000908190600160a01b900460ff16156108ca5760405162461bcd60e51b815260040161088890614011565b603754600160a81b900460ff16156108f45760405162461bcd60e51b815260040161088890614035565b6108ff338585612809565b915091505b9250929050565b6000805160206143278339815191526109238161254b565b6107e482612b02565b6040516355017ca560e11b8152306004820152600090819081906001600160a01b037f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f169063aa02f94a906024016040805180830381865afa158015610996573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ba9190614059565b9150506109c681612b63565b92509250509091565b60007f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c166109fb8161254b565b603754600160a81b900460ff16610a455760405162461bcd60e51b815260206004820152600e60248201526d11d4d357d393d517d4d15256915160921b6044820152606401610888565b60008311610a655760405162461bcd60e51b81526004016108889061407d565b6040516355017ca560e11b81523060048201526000907f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b03169063aa02f94a906024016040805180830381865afa158015610acb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aef9190614059565b91505080841115610afe578093505b6040516323b872dd60e01b8152336004820152306024820152604481018590527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316906323b872dd906064016020604051808303816000875af1158015610b71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9591906140a5565b50604051630852cd8d60e31b8152600481018590527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316906342966c6890602401600060405180830381600087803b158015610bf857600080fd5b505af1158015610c0c573d6000803e3d6000fd5b503392507f40812dae8a8ddfad8bbf45f53c5cdbca587edc4238cbcc7537ae84e204b1c8ae9150869050610c4081856140c2565b6040805192835260208301919091520160405180910390a2839250505b50919050565b603754600090600160a81b900460ff1615610c905760405162461bcd60e51b815260040161088890614035565b7f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c16610cba8161254b565b6037805460ff60a81b1916600160a81b179055603880546001600160801b03169055610ce66000612b02565b6040516355017ca560e11b81523060048201526000907f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b03169063aa02f94a906024016040805180830381865afa158015610d4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d709190614059565b6040516370a0823160e01b8152306004820152909250600091506001600160a01b037f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e16906370a0823190602401602060405180830381865afa158015610ddb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dff91906140d9565b90508015610e4157603654610e41906001600160a01b037f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e8116911683612c40565b60365460408051838152602081018590526001600160a01b039092169133917fe51b546a59a5440500bc9464ab1cb969d07a4508292c32e540ac0f37b644aca8910160405180910390a39250505090565b60025460019060ff1680610ea55750303b155b80610eb1575060015481115b610f145760405162461bcd60e51b815260206004820152602e60248201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560448201526d195b881a5b9a5d1a585b1a5e995960921b6064820152608401610888565b60025460ff16158015610f35576002805460ff191660019081179091558290555b6001600160a01b038516610f845760405162461bcd60e51b815260206004820152601660248201527516915493d7d05111149154d4d7d393d517d59053125160521b6044820152606401610888565b610f8f6000866125f9565b610fa7600080516020614327833981519152866125f9565b610fb084612558565b610fb983612b02565b8015610fca576002805460ff191690555b5050505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6037546000908190600160a01b900460ff16156110295760405162461bcd60e51b815260040161088890614011565b603754600160a81b900460ff16156110535760405162461bcd60e51b815260040161088890614035565b428510156110a35760405162461bcd60e51b815260206004820152601a60248201527f5349474e41545552455f444541444c494e455f455850495245440000000000006044820152606401610888565b60006110ad61267d565b6001600160a01b038a16600090815260356020526040812080547fcfb9ac928a9a202b47d70fc2e62c0dade955274336ca821ed60aeb2142af92e6928d928d928d929091906110fb836140f2565b90915550604080516001600160a01b0395861660208201529081019390935292166060820152608081019190915260a0810189905260c00160408051601f1981840301815290829052611152939291602001614165565b6040516020818303038152906040528051906020012090506111ab898287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612cd192505050565b6111eb5760405162461bcd60e51b815260206004820152601160248201527014d251d3905515549157d2539590531251607a1b6044820152606401610888565b6111f6898989612809565b9250925050965096945050505050565b603754600090600160a81b900460ff16156112335760405162461bcd60e51b815260040161088890614035565b60008051602061432783398151915261124b8161254b565b6000831161126b5760405162461bcd60e51b81526004016108889061407d565b6040516355017ca560e11b81523060048201526000907f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b03169063aa02f94a906024016040805180830381865afa1580156112d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112f59190614059565b915050600061130382612b63565b915050600081116113565760405162461bcd60e51b815260206004820152601a60248201527f4e4f5f43555252454e545f444546494349545f4241434b494e470000000000006044820152606401610888565b60008186116113655785611367565b815b6040516323b872dd60e01b8152336004820152306024820152604481018290529091507f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316906323b872dd906064016020604051808303816000875af11580156113dd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140191906140a5565b50604051630852cd8d60e31b8152600481018290527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316906342966c6890602401600060405180830381600087803b15801561146457600080fd5b505af1158015611478573d6000803e3d6000fd5b50506001600160a01b037f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f1691503390507f4c41558c3fb5d20cbb8485f911a1b9b6e26c6a8ef6f8450ae816463725a65ea383806114d681886140c2565b6040805193845260208401929092529082015260600160405180910390a395945050505050565b6037546000908190819081906001600160a01b031615158181611520578661158d565b6037546040516318fdd06b60e01b8152600481018990526001600160a01b03909116906318fdd06b90602401602060405180830381865afa158015611569573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158d91906140d9565b604051635ded74a560e01b815260048101829052600160248201529091506000906001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b721690635ded74a590604401602060405180830381865afa1580156115ff573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061162391906140d9565b6040516329ede30f60e21b8152600481018290526000602482018190529192506001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b72169063a7b78c3c90604401602060405180830381865afa158015611694573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b891906140d9565b90506000846116c8576000611735565b60375460405163959d6d2960e01b8152600481018490526001600160a01b039091169063959d6d2990602401602060405180830381865afa158015611711573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061173591906140d9565b90508261174282846140c2565b909b909a509198509650945050505050565b6037546000908190819081906001600160a01b03161515818161177757866117e4565b6037546040516352510fd160e11b8152600481018990526001600160a01b039091169063a4a21fa290602401602060405180830381865afa1580156117c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117e491906140d9565b604051635ded74a560e01b8152600481018290526000602482018190529192506001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b721690635ded74a590604401602060405180830381865afa158015611855573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061187991906140d9565b6040516329ede30f60e21b815260048101829052600160248201529091506000906001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b72169063a7b78c3c90604401602060405180830381865afa1580156118eb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061190f91906140d9565b905060008461191f57600061198c565b6037546040516345d6494d60e01b8152600481018490526001600160a01b03909116906345d6494d90602401602060405180830381865afa158015611968573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198c91906140d9565b90508261174282846141a6565b6037546000908190600160a01b900460ff16156119c85760405162461bcd60e51b815260040161088890614011565b603754600160a81b900460ff16156119f25760405162461bcd60e51b815260040161088890614035565b6108ff338585612e15565b603754600090600160a81b900460ff1615611a2a5760405162461bcd60e51b815260040161088890614035565b600080516020614327833981519152611a428161254b565b60008311611a625760405162461bcd60e51b81526004016108889061407d565b6040516355017ca560e11b81523060048201526000907f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b03169063aa02f94a906024016040805180830381865afa158015611ac8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aec9190614059565b9150506000611afa82612b63565b91505060008111611b4d5760405162461bcd60e51b815260206004820152601a60248201527f4e4f5f43555252454e545f444546494349545f4241434b494e470000000000006044820152606401610888565b604051635ded74a560e01b81526004810182905260006024820181905290611be9906001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b721690635ded74a590604401602060405180830381865afa158015611bc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611be491906140d9565b6130fb565b9050806001600160801b03168610611d155780603860108282829054906101000a90046001600160801b0316611c1f91906141be565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550611c8c3330836001600160801b03167f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e6001600160a01b0316613168909392919063ffffffff16565b604080516001600160801b03831681526020810184905260008183015290517f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e6001600160a01b03169133917f4c41558c3fb5d20cbb8485f911a1b9b6e26c6a8ef6f8450ae816463725a65ea39181900360600190a36001600160801b03169350610c5d915050565b6040516329ede30f60e21b815260048101879052600060248201819052907f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b726001600160a01b03169063a7b78c3c90604401602060405180830381865afa158015611d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da891906140d9565b905086603860108282829054906101000a90046001600160801b0316611dce91906141be565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550611e323330897f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e6001600160a01b0316613168909392919063ffffffff16565b6001600160a01b037f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e16337f4c41558c3fb5d20cbb8485f911a1b9b6e26c6a8ef6f8450ae816463725a65ea38984611e8a81896140c2565b6040805193845260208401929092529082015260600160405180910390a386955050505050610c5d565b600080600080611ec385613203565b93509350935093509193509193565b600080516020614327833981519152611eea8161254b565b6107e482613476565b7f6dac4cc0544e34aa1a4ed2862f6de78290e3f18f00fe77179ee8ef34de9dfa24611f1d8161254b565b8115611f7757603754600160a01b900460ff1615611f725760405162461bcd60e51b815260206004820152601260248201527123a9a6afa0a62922a0a22cafa32927ad22a760711b6044820152606401610888565b611fc7565b603754600160a01b900460ff16611fc75760405162461bcd60e51b815260206004820152601460248201527323a9a6afa0a62922a0a22cafaaa7232927ad22a760611b6044820152606401610888565b60378054831515600160a01b0260ff60a01b1990911617905560405133907f2aa23821d2fd7524b53239d5f8398ea59652bbfea171645c0da0dbe82afb5d439061201690851515815260200190565b60405180910390a25050565b600080600080611ec3856134c8565b7fbf63066482b01a20567880b14a2934fecb21c925e6bcc0a0a091c59723fa9c0661205b8161254b565b6000821161207b5760405162461bcd60e51b81526004016108889061407d565b7f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316846001600160a01b0316141561218b576039546040516370a0823160e01b81523060048201526000916001600160801b0316906001600160a01b038716906370a0823190602401602060405180830381865afa158015612109573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212d91906140d9565b61213791906140c2565b9050828110156121895760405162461bcd60e51b815260206004820152601a60248201527f494e53554646494349454e545f47484f5f544f5f5245534355450000000000006044820152606401610888565b505b7f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e6001600160a01b0316846001600160a01b031614156122b1576038546040516370a0823160e01b8152306004820152600091600160801b90046001600160801b0316906001600160a01b038716906370a0823190602401602060405180830381865afa158015612220573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224491906140d9565b61224e91906140c2565b9050828110156122af5760405162461bcd60e51b815260206004820152602660248201527f494e53554646494349454e545f45584f47454e4f55535f41535345545f544f5f60448201526552455343554560d01b6064820152608401610888565b505b6122c56001600160a01b0385168484612c40565b826001600160a01b0316846001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c48460405161230a91815260200190565b60405180910390a350505050565b6000828152602081905260409020600101546123338161254b565b61080d83836127a4565b612345613725565b61234d6138cc565b565b6037546000908190600160a01b900460ff161561237e5760405162461bcd60e51b815260040161088890614011565b603754600160a81b900460ff16156123a85760405162461bcd60e51b815260040161088890614035565b428510156123f85760405162461bcd60e51b815260206004820152601a60248201527f5349474e41545552455f444541444c494e455f455850495245440000000000006044820152606401610888565b600061240261267d565b6001600160a01b038a16600090815260356020526040812080547ff570a3b94987b56be9e62084f59006353309fa95357dfbc6d3ea78cce6382d13928d928d928d92909190612450836140f2565b90915550604080516001600160a01b0395861660208201529081019390935292166060820152608081019190915260a0810189905260c00160408051601f19818403018152908290526124a7939291602001614165565b604051602081830303815290604052805190602001209050612500898287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612cd192505050565b6125405760405162461bcd60e51b815260206004820152601160248201527014d251d3905515549157d2539590531251607a1b6044820152606401610888565b6111f6898989612e15565b61255581336139ee565b50565b6001600160a01b0381166125a75760405162461bcd60e51b815260206004820152601660248201527516915493d7d05111149154d4d7d393d517d59053125160521b6044820152606401610888565b603680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f13f4413d8d93a259bd6c10f35095371f30ed50f81a73407e52e9f02000d5d16b90600090a35050565b6126038282610fd1565b6107e4576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556126393390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000306001600160a01b037f0000000000000000000000002edfb4eb6a7fb78b3ac9204f179510865d77c660161480156126d657507f000000000000000000000000000000000000000000000000000000000000000146145b1561270057507fac19cac8fcabb03e74c30391ea683bd9231127ff4804262a7ab9f3bd894e166890565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f75b3310af9b713b9bc9fef8cd0b585229d2e229644a8175e6b110c4f932640a8828401527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a0808401919091528351808403909101815260c0909201909252805191012090565b6127ae8282610fd1565b156107e4576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60008060008060008061281b886134c8565b935093509350935061282e898589613a47565b6000841161284e5760405162461bcd60e51b81526004016108889061407d565b603854600160801b90046001600160801b03168411156128c95760405162461bcd60e51b815260206004820152603060248201527f494e53554646494349454e545f415641494c41424c455f45584f47454e4f555360448201526f5f41535345545f4c495155494449545960801b6064820152608401610888565b83603860108282829054906101000a90046001600160801b03166128ed9190613fe9565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555061291a816130fb565b603980546000906129359084906001600160801b03166141be565b82546001600160801b039182166101009390930a9283029190920219909116179055506040516323b872dd60e01b81526001600160a01b038a81166004830152306024830152604482018590527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f16906323b872dd906064016020604051808303816000875af11580156129cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f191906140a5565b50604051630852cd8d60e31b8152600481018390527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316906342966c6890602401600060405180830381600087803b158015612a5457600080fd5b505af1158015612a68573d6000803e3d6000fd5b50612aa29250506001600160a01b037f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e1690508886612c40565b60408051858152602081018590529081018290526001600160a01b0380891691908b16907f35b18eb91d0f8ce2968fdf81c1ed9ac429776c7260cdb8bf35c314564e714f66906060015b60405180910390a3509197909650945050505050565b603880546001600160801b038381166001600160801b031983168117909355604080519190921680825260208201939093527fe0f222fd3dc07d1f2556e7d34819cc5fe0ab68fedb472dc2de611aa3398409ce910160405180910390a15050565b6038546040516329ede30f60e21b8152600160801b9091046001600160801b0316600482015260006024820181905290819081907f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b726001600160a01b03169063a7b78c3c90604401602060405180830381865afa158015612be8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c0c91906140d9565b9050838110612c2a57612c1f84826140c2565b946000945092505050565b6000612c3682866140c2565b9250925050915091565b60405163a9059cbb60e01b8082526001600160a01b0384166004830152602482018390529060008060448382895af1612c7d573d6000803e3d6000fd5b50612c8784613a4f565b612ccb5760405162461bcd60e51b815260206004820152601560248201527423a83b191d103330b4b632b2103a3930b739b332b960591b6044820152606401610888565b50505050565b6000806000612ce08585613af6565b90925090506000816004811115612cf957612cf96141e9565b148015612d175750856001600160a01b0316826001600160a01b0316145b15612d2757600192505050612e0e565b600080876001600160a01b0316631626ba7e60e01b8888604051602401612d4f9291906141ff565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612d8d9190614220565b600060405180830381855afa9150503d8060008114612dc8576040519150601f19603f3d011682016040523d82523d6000602084013e612dcd565b606091505b5091509150818015612de0575080516020145b8015612e0757508051630b135d3f60e11b90612e0590830160209081019084016140d9565b145b9450505050505b9392505050565b600080600080600080612e2788613203565b935093509350935060008411612e4f5760405162461bcd60e51b81526004016108889061407d565b6038546001600160801b0380821691612e71918791600160801b9004166141a6565b1115612ec95760405162461bcd60e51b815260206004820152602160248201527f45584f47454e4f55535f41535345545f4558504f535552455f544f4f5f4849476044820152600960fb1b6064820152608401610888565b83603860108282829054906101000a90046001600160801b0316612eed91906141be565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550612f1a816130fb565b60398054600090612f359084906001600160801b03166141be565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550612f998930867f000000000000000000000000d4fa2d31b7968e448877f69a96de69f5de8cd23e6001600160a01b0316613168909392919063ffffffff16565b6040516340c10f1960e01b8152306004820152602481018390527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f6001600160a01b0316906340c10f1990604401600060405180830381600087803b15801561300157600080fd5b505af1158015613015573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038a81166004830152602482018790527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f16925063a9059cbb91506044016020604051808303816000875af1158015613088573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ac91906140a5565b5060408051858152602081018490529081018290526001600160a01b0380891691908b16907fefd9053c6d75eeb7635ae405072e58d5d1588e1ee0db5d212e6afcb529b975e390606001612aec565b60006001600160801b038211156131645760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610888565b5090565b6040516323b872dd60e01b8082526001600160a01b038581166004840152841660248301526044820183905290600080606483828a5af16131ad573d6000803e3d6000fd5b506131b785613a4f565b610fca5760405162461bcd60e51b815260206004820152601960248201527f475076323a206661696c6564207472616e7366657246726f6d000000000000006044820152606401610888565b6037546040516329ede30f60e21b815260048101839052600060248201819052918291829182916001600160a01b0391821615159183917f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b729091169063a7b78c3c90604401602060405180830381865afa158015613285573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132a991906140d9565b90506000826132b9576000613326565b60375460405163959d6d2960e01b8152600481018490526001600160a01b039091169063959d6d2990602401602060405180830381865afa158015613302573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061332691906140d9565b9050600061333482846140c2565b905060008461334357816133b0565b6037546040516318fdd06b60e01b8152600481018490526001600160a01b03909116906318fdd06b90602401602060405180830381865afa15801561338c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133b091906140d9565b604051635ded74a560e01b815260048101829052600160248201529091506000906001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b721690635ded74a590604401602060405180830381865afa158015613422573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061344691906140d9565b9050600061345484846140c2565b90508161346182856140c2565b909d909c50929a509850909650505050505050565b603780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8a53d8a38ee2969ab6c2a4793fc6d15aac23906030c4943495dd2e843b48f9d690600090a35050565b6037546040516329ede30f60e21b815260048101839052600160248201526000918291829182916001600160a01b0391821615159183917f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b729091169063a7b78c3c90604401602060405180830381865afa15801561354a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061356e91906140d9565b905060008261357e5760006135eb565b6037546040516345d6494d60e01b8152600481018490526001600160a01b03909116906345d6494d90602401602060405180830381865afa1580156135c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135eb91906140d9565b905060006135f982846141a6565b90506000846136085781613675565b6037546040516352510fd160e11b8152600481018490526001600160a01b039091169063a4a21fa290602401602060405180830381865afa158015613651573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061367591906140d9565b604051635ded74a560e01b8152600481018290526000602482018190529192506001600160a01b037f00000000000000000000000000e89f4022fd13ad56e321d50612eec598ef3b721690635ded74a590604401602060405180830381865afa1580156136e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061370a91906140d9565b9050600061371883856140c2565b90508161346182856141a6565b6040516355017ca560e11b815230600482015260009081906001600160a01b037f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f169063aa02f94a906024016040805180830381865afa15801561378d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137b19190614059565b9150915060008183116137c55760006137cf565b6137cf82846140c2565b905060006137dc83612b63565b5090506000811180156137ef5750600082115b15612ccb578181116138015780613803565b815b6039805491925082916000906138239084906001600160801b03166141be565b82546001600160801b039182166101009390930a9283029190920219909116179055506040516340c10f1960e01b8152306004820152602481018290526001600160a01b037f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f16906340c10f1990604401600060405180830381600087803b1580156138ae57600080fd5b505af11580156138c2573d6000803e3d6000fd5b5050505050505050565b6039546001600160801b0316801561255557603980546001600160801b031916905560365460405163a9059cbb60e01b81526001600160a01b039182166004820152602481018390527f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f9091169063a9059cbb906044016020604051808303816000875af1158015613962573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061398691906140a5565b506036546040518281526001600160a01b037f00000000000000000000000040d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f81169216907fb29fcda740927812f5a71075b62e132bead3769a455319c29b9a1cc461a654759060200160405180910390a350565b6139f88282610fd1565b6107e457613a0581613b39565b613a10836020613b4b565b604051602001613a2192919061423c565b60408051601f198184030181529082905262461bcd60e51b8252610888916004016142b1565b61080d613725565b6000613a75565b62461bcd60e51b60005260206004528060245250806044525060646000fd5b3d8015613ab45760208114613ae557613aaf7f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f613a56565b610c5d565b823b613adc57613adc7311d41d8c8e881b9bdd08184818dbdb9d1c9858dd60621b6014613a56565b60019150610c5d565b3d6000803e50506000511515919050565b600080825160411415613b2d5760208301516040840151606085015160001a613b2187828585613ce7565b94509450505050610904565b50600090506002610904565b606061073f6001600160a01b03831660145b60606000613b5a8360026142c4565b613b659060026141a6565b67ffffffffffffffff811115613b7d57613b7d6142e3565b6040519080825280601f01601f191660200182016040528015613ba7576020820181803683370190505b509050600360fc1b81600081518110613bc257613bc26142f9565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613bf157613bf16142f9565b60200101906001600160f81b031916908160001a9053506000613c158460026142c4565b613c209060016141a6565b90505b6001811115613c98576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613c5457613c546142f9565b1a60f81b828281518110613c6a57613c6a6142f9565b60200101906001600160f81b031916908160001a90535060049490941c93613c918161430f565b9050613c23565b508315612e0e5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610888565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613d1e5750600090506003613da2565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015613d72573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613d9b57600060019250925050613da2565b9150600090505b94509492505050565b600060208284031215613dbd57600080fd5b81356001600160e01b031981168114612e0e57600080fd5b80356001600160a01b0381168114613dec57600080fd5b919050565b600060208284031215613e0357600080fd5b612e0e82613dd5565b600060208284031215613e1e57600080fd5b5035919050565b60008060408385031215613e3857600080fd5b82359150613e4860208401613dd5565b90509250929050565b80356001600160801b0381168114613dec57600080fd5b600060208284031215613e7a57600080fd5b612e0e82613e51565b600080600060608486031215613e9857600080fd5b613ea184613dd5565b9250613eaf60208501613dd5565b9150613ebd60408501613e51565b90509250925092565b60008060008060008060a08789031215613edf57600080fd5b613ee887613dd5565b955060208701359450613efd60408801613dd5565b935060608701359250608087013567ffffffffffffffff80821115613f2157600080fd5b818901915089601f830112613f3557600080fd5b813581811115613f4457600080fd5b8a6020828501011115613f5657600080fd5b6020830194508093505050509295509295509295565b801515811461255557600080fd5b600060208284031215613f8c57600080fd5b8135612e0e81613f6c565b600080600060608486031215613fac57600080fd5b613fb584613dd5565b9250613fc360208501613dd5565b9150604084013590509250925092565b634e487b7160e01b600052601160045260246000fd5b60006001600160801b038381169083168181101561400957614009613fd3565b039392505050565b6020808252600a908201526923a9a6afa32927ad22a760b11b604082015260600190565b6020808252600a908201526911d4d357d4d15256915160b21b604082015260600190565b6000806040838503121561406c57600080fd5b505080516020909101519092909150565b6020808252600e908201526d1253959053125117d05353d5539560921b604082015260600190565b6000602082840312156140b757600080fd5b8151612e0e81613f6c565b6000828210156140d4576140d4613fd3565b500390565b6000602082840312156140eb57600080fd5b5051919050565b600060001982141561410657614106613fd3565b5060010190565b60005b83811015614128578181015183820152602001614110565b83811115612ccb5750506000910152565b6000815180845261415181602086016020860161410d565b601f01601f19169290920160200192915050565b608081526002608082015261190160f01b60a082015283602082015282604082015260c06060820152600061419d60c0830184614139565b95945050505050565b600082198211156141b9576141b9613fd3565b500190565b60006001600160801b038083168185168083038211156141e0576141e0613fd3565b01949350505050565b634e487b7160e01b600052602160045260246000fd5b8281526040602082015260006142186040830184614139565b949350505050565b6000825161423281846020870161410d565b9190910192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161427481601785016020880161410d565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516142a581602884016020880161410d565b01602801949350505050565b602081526000612e0e6020830184614139565b60008160001904831182151516156142de576142de613fd3565b500290565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008161431e5761431e613fd3565b50600019019056fe3b49a237fe2d18fa4d9642b8a0e065923cceb71b797783b619a030a61d848bf0a26469706673582212203076eaf6ce9f6704da288b8938ba5141241c31ba31e7ec584ffa22bb9b18520964736f6c634300080a0033
Verified Source Code Partial Match
Compiler: v0.8.10+commit.fc410830
EVM: london
Optimization: Yes (200 runs)
Gsm4626.sol 151 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {IERC20} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {GPv2SafeERC20} from '@aave/core-v3/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';
import {IGhoFacilitator} from '../../gho/interfaces/IGhoFacilitator.sol';
import {IGhoToken} from '../../gho/interfaces/IGhoToken.sol';
import {IGsmPriceStrategy} from './priceStrategy/interfaces/IGsmPriceStrategy.sol';
import {IGsm4626} from './interfaces/IGsm4626.sol';
import {Gsm} from './Gsm.sol';
/**
* @title Gsm4626
* @author Aave
* @notice GHO Stability Module for ERC4626 vault shares. It provides buy/sell facilities to go to/from an ERC4626
* vault share to/from GHO.
* @dev Aimed to be used with ERC4626 vault shares as underlying asset. Users can use the ERC4626 vault share to
* buy/sell GHO and the generated yield is redirected to the GHO Treasury in form of GHO.
* @dev To be covered by a proxy contract.
*/
contract Gsm4626 is Gsm, IGsm4626 {
using GPv2SafeERC20 for IERC20;
using SafeCast for uint256;
/**
* @dev Constructor
* @param ghoToken The address of the GHO token contract
* @param underlyingAsset The address of the ERC4626 vault
* @param priceStrategy The address of the price strategy
*/
constructor(
address ghoToken,
address underlyingAsset,
address priceStrategy
) Gsm(ghoToken, underlyingAsset, priceStrategy) {
// Intentionally left blank
}
/// @inheritdoc IGsm4626
function backWithGho(
uint256 amount
) external notSeized onlyRole(CONFIGURATOR_ROLE) returns (uint256) {
require(amount > 0, 'INVALID_AMOUNT');
(, uint256 ghoMinted) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(address(this));
(, uint256 deficit) = _getCurrentBacking(ghoMinted);
require(deficit > 0, 'NO_CURRENT_DEFICIT_BACKING');
uint256 ghoToBack = amount > deficit ? deficit : amount;
IGhoToken(GHO_TOKEN).transferFrom(msg.sender, address(this), ghoToBack);
IGhoToken(GHO_TOKEN).burn(ghoToBack);
emit BackingProvided(msg.sender, GHO_TOKEN, ghoToBack, ghoToBack, deficit - ghoToBack);
return ghoToBack;
}
/// @inheritdoc IGsm4626
function backWithUnderlying(
uint256 amount
) external notSeized onlyRole(CONFIGURATOR_ROLE) returns (uint256) {
require(amount > 0, 'INVALID_AMOUNT');
(, uint256 ghoMinted) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(address(this));
(, uint256 deficit) = _getCurrentBacking(ghoMinted);
require(deficit > 0, 'NO_CURRENT_DEFICIT_BACKING');
uint128 deficitInUnderlying = IGsmPriceStrategy(PRICE_STRATEGY)
.getGhoPriceInAsset(deficit, false)
.toUint128();
if (amount >= deficitInUnderlying) {
_currentExposure += deficitInUnderlying;
IERC20(UNDERLYING_ASSET).safeTransferFrom(msg.sender, address(this), deficitInUnderlying);
emit BackingProvided(msg.sender, UNDERLYING_ASSET, deficitInUnderlying, deficit, 0);
return deficitInUnderlying;
} else {
uint256 amountInGho = IGsmPriceStrategy(PRICE_STRATEGY).getAssetPriceInGho(amount, false);
_currentExposure += uint128(amount);
IERC20(UNDERLYING_ASSET).safeTransferFrom(msg.sender, address(this), amount);
emit BackingProvided(
msg.sender,
UNDERLYING_ASSET,
amount,
amountInGho,
deficit - amountInGho
);
return amount;
}
}
/// @inheritdoc IGsm4626
function getCurrentBacking() external view returns (uint256, uint256) {
(, uint256 ghoMinted) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(address(this));
return _getCurrentBacking(ghoMinted);
}
/// @inheritdoc IGhoFacilitator
function distributeFeesToTreasury() public override(Gsm, IGhoFacilitator) {
_cumulateYieldInGho();
super.distributeFeesToTreasury();
}
/// @inheritdoc Gsm
function _beforeBuyAsset(address, uint256, address) internal override {
_cumulateYieldInGho();
}
/// @inheritdoc Gsm
function _beforeSellAsset(address, uint256, address) internal override {}
/**
* @dev Cumulates yield in form of GHO, aimed to be redirected to the treasury
* @dev It mints GHO backed by the excess of underlying produced by the ERC4626 yield
* @dev If the GHO amount exceeds the amount available, it will mint up to the remaining capacity
*/
function _cumulateYieldInGho() internal {
(uint256 ghoCapacity, uint256 ghoLevel) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(
address(this)
);
uint256 ghoAvailableToMint = ghoCapacity > ghoLevel ? ghoCapacity - ghoLevel : 0;
(uint256 ghoExcess, ) = _getCurrentBacking(ghoLevel);
if (ghoExcess > 0 && ghoAvailableToMint > 0) {
ghoExcess = ghoExcess > ghoAvailableToMint ? ghoAvailableToMint : ghoExcess;
_accruedFees += uint128(ghoExcess);
IGhoToken(GHO_TOKEN).mint(address(this), ghoExcess);
}
}
/**
* @dev Calculates the excess or deficit of GHO minted, reflective of GSM backing
* @param ghoMinted The amount of GHO currently minted by the GSM
* @return The excess amount of GHO minted, relative to the value of the underlying
* @return The deficit of GHO minted, relative to the value of the underlying
*/
function _getCurrentBacking(uint256 ghoMinted) internal view returns (uint256, uint256) {
uint256 ghoToBack = IGsmPriceStrategy(PRICE_STRATEGY).getAssetPriceInGho(
_currentExposure,
false
);
if (ghoToBack >= ghoMinted) {
return (ghoToBack - ghoMinted, 0);
} else {
return (0, ghoMinted - ghoToBack);
}
}
}
IERC20.sol 80 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
GPv2SafeERC20.sol 124 lines
// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity 0.8.10;
import {IERC20} from '../../openzeppelin/contracts/IERC20.sol';
/// @title Gnosis Protocol v2 Safe ERC20 Transfer Library
/// @author Gnosis Developers
/// @dev Gas-efficient version of Openzeppelin's SafeERC20 contract.
library GPv2SafeERC20 {
/// @dev Wrapper around a call to the ERC20 function `transfer` that reverts
/// also when the token returns `false`.
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
bytes4 selector_ = token.transfer.selector;
// solhint-disable-next-line no-inline-assembly
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, selector_)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), value)
if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
require(getLastTransferResult(token), 'GPv2: failed transfer');
}
/// @dev Wrapper around a call to the ERC20 function `transferFrom` that
/// reverts also when the token returns `false`.
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
bytes4 selector_ = token.transferFrom.selector;
// solhint-disable-next-line no-inline-assembly
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, selector_)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 68), value)
if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)) {
returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())
}
}
require(getLastTransferResult(token), 'GPv2: failed transferFrom');
}
/// @dev Verifies that the last return was a successful `transfer*` call.
/// This is done by checking that the return data is either empty, or
/// is a valid ABI encoded boolean.
function getLastTransferResult(IERC20 token) private view returns (bool success) {
// NOTE: Inspecting previous return data requires assembly. Note that
// we write the return data to memory 0 in the case where the return
// data size is 32, this is OK since the first 64 bytes of memory are
// reserved by Solidy as a scratch space that can be used within
// assembly blocks.
// <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html>
// solhint-disable-next-line no-inline-assembly
assembly {
/// @dev Revert with an ABI encoded Solidity error with a message
/// that fits into 32-bytes.
///
/// An ABI encoded Solidity error has the following memory layout:
///
/// ------------+----------------------------------
/// byte range | value
/// ------------+----------------------------------
/// 0x00..0x04 | selector("Error(string)")
/// 0x04..0x24 | string offset (always 0x20)
/// 0x24..0x44 | string length
/// 0x44..0x64 | string value, padded to 32-bytes
function revertWithMessage(length, message) {
mstore(0x00, '\x08\xc3\x79\xa0')
mstore(0x04, 0x20)
mstore(0x24, length)
mstore(0x44, message)
revert(0x00, 0x64)
}
switch returndatasize()
// Non-standard ERC20 transfer without return.
case 0 {
// NOTE: When the return data size is 0, verify that there
// is code at the address. This is done in order to maintain
// compatibility with Solidity calling conventions.
// <https://docs.soliditylang.org/en/v0.7.6/control-structures.html#external-function-calls>
if iszero(extcodesize(token)) {
revertWithMessage(20, 'GPv2: not a contract')
}
success := 1
}
// Standard ERC20 transfer returning boolean success value.
case 32 {
returndatacopy(0, 0, returndatasize())
// NOTE: For ABI encoding v1, any non-zero value is accepted
// as `true` for a boolean. In order to stay compatible with
// OpenZeppelin's `SafeERC20` library which is known to work
// with the existing ERC20 implementation we care about,
// make sure we return success for any non-zero return value
// from the `transfer*` call.
success := iszero(iszero(mload(0)))
}
default {
revertWithMessage(31, 'GPv2: malformed transfer result')
}
}
}
}
SafeCast.sol 1136 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX 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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @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
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
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
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
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
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
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
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
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
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
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
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
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
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
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
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
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
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
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
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
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
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
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
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
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
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
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
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
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
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
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
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
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
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
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
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
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
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
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
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
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
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
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
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
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
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
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
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
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
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
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
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
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
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
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
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
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
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
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
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
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
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
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
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
IGhoFacilitator.sol 46 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IGhoFacilitator
* @author Aave
* @notice Defines the behavior of a Gho Facilitator
*/
interface IGhoFacilitator {
/**
* @dev Emitted when fees are distributed to the GhoTreasury
* @param ghoTreasury The address of the ghoTreasury
* @param asset The address of the asset transferred to the ghoTreasury
* @param amount The amount of the asset transferred to the ghoTreasury
*/
event FeesDistributedToTreasury(
address indexed ghoTreasury,
address indexed asset,
uint256 amount
);
/**
* @dev Emitted when Gho Treasury address is updated
* @param oldGhoTreasury The address of the old GhoTreasury contract
* @param newGhoTreasury The address of the new GhoTreasury contract
*/
event GhoTreasuryUpdated(address indexed oldGhoTreasury, address indexed newGhoTreasury);
/**
* @notice Distribute fees to the GhoTreasury
*/
function distributeFeesToTreasury() external;
/**
* @notice Updates the address of the Gho Treasury
* @dev WARNING: The GhoTreasury is where revenue fees are sent to. Update carefully
* @param newGhoTreasury The address of the GhoTreasury
*/
function updateGhoTreasury(address newGhoTreasury) external;
/**
* @notice Returns the address of the Gho Treasury
* @return The address of the GhoTreasury contract
*/
function getGhoTreasury() external view returns (address);
}
IGhoToken.sol 137 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {IAccessControl} from '@openzeppelin/contracts/access/IAccessControl.sol';
/**
* @title IGhoToken
* @author Aave
*/
interface IGhoToken is IERC20, IAccessControl {
struct Facilitator {
uint128 bucketCapacity;
uint128 bucketLevel;
string label;
}
/**
* @dev Emitted when a new facilitator is added
* @param facilitatorAddress The address of the new facilitator
* @param label A hashed human readable identifier for the facilitator
* @param bucketCapacity The initial capacity of the facilitator's bucket
*/
event FacilitatorAdded(
address indexed facilitatorAddress,
bytes32 indexed label,
uint256 bucketCapacity
);
/**
* @dev Emitted when a facilitator is removed
* @param facilitatorAddress The address of the removed facilitator
*/
event FacilitatorRemoved(address indexed facilitatorAddress);
/**
* @dev Emitted when the bucket capacity of a facilitator is updated
* @param facilitatorAddress The address of the facilitator whose bucket capacity is being changed
* @param oldCapacity The old capacity of the bucket
* @param newCapacity The new capacity of the bucket
*/
event FacilitatorBucketCapacityUpdated(
address indexed facilitatorAddress,
uint256 oldCapacity,
uint256 newCapacity
);
/**
* @dev Emitted when the bucket level changed
* @param facilitatorAddress The address of the facilitator whose bucket level is being changed
* @param oldLevel The old level of the bucket
* @param newLevel The new level of the bucket
*/
event FacilitatorBucketLevelUpdated(
address indexed facilitatorAddress,
uint256 oldLevel,
uint256 newLevel
);
/**
* @notice Returns the identifier of the Facilitator Manager Role
* @return The bytes32 id hash of the FacilitatorManager role
*/
function FACILITATOR_MANAGER_ROLE() external pure returns (bytes32);
/**
* @notice Returns the identifier of the Bucket Manager Role
* @return The bytes32 id hash of the BucketManager role
*/
function BUCKET_MANAGER_ROLE() external pure returns (bytes32);
/**
* @notice Mints the requested amount of tokens to the account address.
* @dev Only facilitators with enough bucket capacity available can mint.
* @dev The bucket level is increased upon minting.
* @param account The address receiving the GHO tokens
* @param amount The amount to mint
*/
function mint(address account, uint256 amount) external;
/**
* @notice Burns the requested amount of tokens from the account address.
* @dev Only active facilitators (bucket level > 0) can burn.
* @dev The bucket level is decreased upon burning.
* @param amount The amount to burn
*/
function burn(uint256 amount) external;
/**
* @notice Add the facilitator passed with the parameters to the facilitators list.
* @dev Only accounts with `FACILITATOR_MANAGER_ROLE` role can call this function
* @param facilitatorAddress The address of the facilitator to add
* @param facilitatorLabel A human readable identifier for the facilitator
* @param bucketCapacity The upward limit of GHO can be minted by the facilitator
*/
function addFacilitator(
address facilitatorAddress,
string calldata facilitatorLabel,
uint128 bucketCapacity
) external;
/**
* @notice Remove the facilitator from the facilitators list.
* @dev Only accounts with `FACILITATOR_MANAGER_ROLE` role can call this function
* @param facilitatorAddress The address of the facilitator to remove
*/
function removeFacilitator(address facilitatorAddress) external;
/**
* @notice Set the bucket capacity of the facilitator.
* @dev Only accounts with `BUCKET_MANAGER_ROLE` role can call this function
* @param facilitator The address of the facilitator
* @param newCapacity The new capacity of the bucket
*/
function setFacilitatorBucketCapacity(address facilitator, uint128 newCapacity) external;
/**
* @notice Returns the facilitator data
* @param facilitator The address of the facilitator
* @return The facilitator configuration
*/
function getFacilitator(address facilitator) external view returns (Facilitator memory);
/**
* @notice Returns the bucket configuration of the facilitator
* @param facilitator The address of the facilitator
* @return The capacity of the facilitator's bucket
* @return The level of the facilitator's bucket
*/
function getFacilitatorBucket(address facilitator) external view returns (uint256, uint256);
/**
* @notice Returns the list of the addresses of the active facilitator
* @return The list of the facilitators addresses
*/
function getFacilitatorsList() external view returns (address[] memory);
}
IGsmPriceStrategy.sol 43 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IGsmPriceStrategy
* @author Aave
* @notice Defines the behaviour of Price Strategies
*/
interface IGsmPriceStrategy {
/**
* @notice Returns the number of decimals of GHO
* @return The number of decimals of GHO
*/
function GHO_DECIMALS() external view returns (uint256);
/**
* @notice Returns the address of the underlying asset being priced
* @return The address of the underlying asset
*/
function UNDERLYING_ASSET() external view returns (address);
/**
* @notice Returns the decimals of the underlying asset being priced
* @return The number of decimals of the underlying asset
*/
function UNDERLYING_ASSET_DECIMALS() external view returns (uint256);
/**
* @notice Returns the price of the underlying asset (GHO denominated)
* @param assetAmount The amount of the underlying asset to calculate the price of
* @param roundUp True if the price should be rounded up, false if rounded down
* @return The price of the underlying asset (expressed in GHO units)
*/
function getAssetPriceInGho(uint256 assetAmount, bool roundUp) external view returns (uint256);
/**
* @notice Returns the price of GHO (denominated in the underlying asset)
* @param ghoAmount The amount of GHO to calculate the price of
* @param roundUp True if the price should be rounded up, false if rounded down
* @return The price of the GHO amount (expressed in underlying asset units)
*/
function getGhoPriceInAsset(uint256 ghoAmount, bool roundUp) external view returns (uint256);
}
IGsm4626.sol 52 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IGsm} from './IGsm.sol';
/**
* @title IGsm4626
* @author Aave
* @notice Defines the behaviour of a GHO Stability Module with an ERC-4626 underlying asset
*/
interface IGsm4626 is IGsm {
/**
* @dev Emitted when an asset is provided to the GSM to backstop a loss
* @param backer The address of the backer
* @param asset The address of the provided asset
* @param amount The amount of the asset
* @param ghoAmount The amount of the asset, in GHO terms
* @param remainingLoss The loss balance that remains after the operation
*/
event BackingProvided(
address indexed backer,
address indexed asset,
uint256 amount,
uint256 ghoAmount,
uint256 remainingLoss
);
/**
* @notice Restores backing of GHO by burning GHO
* @dev Useful in the event the underlying value declines relative to GHO minted
* @dev Passing an amount higher than the current deficit will result in backing the entire deficit
* @param amount The amount of GHO to be burned
* @return The amount of GHO used for backing
*/
function backWithGho(uint256 amount) external returns (uint256);
/**
* @notice Restores backing of GHO by providing underlying asset
* @dev Useful in the event the underlying value declines relative to GHO minted
* @dev Passing an amount higher than the current deficit will result in backing the entire deficit
* @param amount The amount of underlying to be used for backing
* @return The amount of underlying used for backing
*/
function backWithUnderlying(uint256 amount) external returns (uint256);
/**
* @notice Returns the excess or deficit of GHO, reflecting current GSM backing
* @return The excess amount of GHO minted, relative to the value of the underlying
* @return The deficit of GHO minted, relative to the value of the underlying
*/
function getCurrentBacking() external view returns (uint256, uint256);
}
Gsm.sol 565 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {VersionedInitializable} from '@aave/core-v3/contracts/protocol/libraries/aave-upgradeability/VersionedInitializable.sol';
import {IERC20} from '@aave/core-v3/contracts/dependencies/openzeppelin/contracts/IERC20.sol';
import {GPv2SafeERC20} from '@aave/core-v3/contracts/dependencies/gnosis/contracts/GPv2SafeERC20.sol';
import {EIP712} from '@openzeppelin/contracts/utils/cryptography/EIP712.sol';
import {SignatureChecker} from '@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol';
import {SafeCast} from '@openzeppelin/contracts/utils/math/SafeCast.sol';
import {AccessControl} from '@openzeppelin/contracts/access/AccessControl.sol';
import {IGhoFacilitator} from '../../gho/interfaces/IGhoFacilitator.sol';
import {IGhoToken} from '../../gho/interfaces/IGhoToken.sol';
import {IGsmPriceStrategy} from './priceStrategy/interfaces/IGsmPriceStrategy.sol';
import {IGsmFeeStrategy} from './feeStrategy/interfaces/IGsmFeeStrategy.sol';
import {IGsm} from './interfaces/IGsm.sol';
/**
* @title Gsm
* @author Aave
* @notice GHO Stability Module. It provides buy/sell facilities to go to/from an underlying asset to/from GHO.
* @dev To be covered by a proxy contract.
*/
contract Gsm is AccessControl, VersionedInitializable, EIP712, IGsm {
using GPv2SafeERC20 for IERC20;
using SafeCast for uint256;
/// @inheritdoc IGsm
bytes32 public constant CONFIGURATOR_ROLE = keccak256('CONFIGURATOR_ROLE');
/// @inheritdoc IGsm
bytes32 public constant TOKEN_RESCUER_ROLE = keccak256('TOKEN_RESCUER_ROLE');
/// @inheritdoc IGsm
bytes32 public constant SWAP_FREEZER_ROLE = keccak256('SWAP_FREEZER_ROLE');
/// @inheritdoc IGsm
bytes32 public constant LIQUIDATOR_ROLE = keccak256('LIQUIDATOR_ROLE');
/// @inheritdoc IGsm
bytes32 public constant BUY_ASSET_WITH_SIG_TYPEHASH =
keccak256(
'BuyAssetWithSig(address originator,uint256 minAmount,address receiver,uint256 nonce,uint256 deadline)'
);
/// @inheritdoc IGsm
bytes32 public constant SELL_ASSET_WITH_SIG_TYPEHASH =
keccak256(
'SellAssetWithSig(address originator,uint256 maxAmount,address receiver,uint256 nonce,uint256 deadline)'
);
/// @inheritdoc IGsm
address public immutable GHO_TOKEN;
/// @inheritdoc IGsm
address public immutable UNDERLYING_ASSET;
/// @inheritdoc IGsm
address public immutable PRICE_STRATEGY;
/// @inheritdoc IGsm
mapping(address => uint256) public nonces;
address internal _ghoTreasury;
address internal _feeStrategy;
bool internal _isFrozen;
bool internal _isSeized;
uint128 internal _exposureCap;
uint128 internal _currentExposure;
uint128 internal _accruedFees;
/**
* @dev Require GSM to not be frozen for functions marked by this modifier
*/
modifier notFrozen() {
require(!_isFrozen, 'GSM_FROZEN');
_;
}
/**
* @dev Require GSM to not be seized for functions marked by this modifier
*/
modifier notSeized() {
require(!_isSeized, 'GSM_SEIZED');
_;
}
/**
* @dev Constructor
* @param ghoToken The address of the GHO token contract
* @param underlyingAsset The address of the collateral asset
* @param priceStrategy The address of the price strategy
*/
constructor(address ghoToken, address underlyingAsset, address priceStrategy) EIP712('GSM', '1') {
require(ghoToken != address(0), 'ZERO_ADDRESS_NOT_VALID');
require(underlyingAsset != address(0), 'ZERO_ADDRESS_NOT_VALID');
require(
IGsmPriceStrategy(priceStrategy).UNDERLYING_ASSET() == underlyingAsset,
'INVALID_PRICE_STRATEGY'
);
GHO_TOKEN = ghoToken;
UNDERLYING_ASSET = underlyingAsset;
PRICE_STRATEGY = priceStrategy;
}
/**
* @notice GSM initializer
* @param admin The address of the default admin role
* @param ghoTreasury The address of the GHO treasury
* @param exposureCap Maximum amount of user-supplied underlying asset in GSM
*/
function initialize(
address admin,
address ghoTreasury,
uint128 exposureCap
) external initializer {
require(admin != address(0), 'ZERO_ADDRESS_NOT_VALID');
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(CONFIGURATOR_ROLE, admin);
_updateGhoTreasury(ghoTreasury);
_updateExposureCap(exposureCap);
}
/// @inheritdoc IGsm
function buyAsset(
uint256 minAmount,
address receiver
) external notFrozen notSeized returns (uint256, uint256) {
return _buyAsset(msg.sender, minAmount, receiver);
}
/// @inheritdoc IGsm
function buyAssetWithSig(
address originator,
uint256 minAmount,
address receiver,
uint256 deadline,
bytes calldata signature
) external notFrozen notSeized returns (uint256, uint256) {
require(deadline >= block.timestamp, 'SIGNATURE_DEADLINE_EXPIRED');
bytes32 digest = keccak256(
abi.encode(
'\x19\x01',
_domainSeparatorV4(),
BUY_ASSET_WITH_SIG_TYPEHASH,
abi.encode(originator, minAmount, receiver, nonces[originator]++, deadline)
)
);
require(
SignatureChecker.isValidSignatureNow(originator, digest, signature),
'SIGNATURE_INVALID'
);
return _buyAsset(originator, minAmount, receiver);
}
/// @inheritdoc IGsm
function sellAsset(
uint256 maxAmount,
address receiver
) external notFrozen notSeized returns (uint256, uint256) {
return _sellAsset(msg.sender, maxAmount, receiver);
}
/// @inheritdoc IGsm
function sellAssetWithSig(
address originator,
uint256 maxAmount,
address receiver,
uint256 deadline,
bytes calldata signature
) external notFrozen notSeized returns (uint256, uint256) {
require(deadline >= block.timestamp, 'SIGNATURE_DEADLINE_EXPIRED');
bytes32 digest = keccak256(
abi.encode(
'\x19\x01',
_domainSeparatorV4(),
SELL_ASSET_WITH_SIG_TYPEHASH,
abi.encode(originator, maxAmount, receiver, nonces[originator]++, deadline)
)
);
require(
SignatureChecker.isValidSignatureNow(originator, digest, signature),
'SIGNATURE_INVALID'
);
return _sellAsset(originator, maxAmount, receiver);
}
/// @inheritdoc IGsm
function rescueTokens(
address token,
address to,
uint256 amount
) external onlyRole(TOKEN_RESCUER_ROLE) {
require(amount > 0, 'INVALID_AMOUNT');
if (token == GHO_TOKEN) {
uint256 rescuableBalance = IERC20(token).balanceOf(address(this)) - _accruedFees;
require(rescuableBalance >= amount, 'INSUFFICIENT_GHO_TO_RESCUE');
}
if (token == UNDERLYING_ASSET) {
uint256 rescuableBalance = IERC20(token).balanceOf(address(this)) - _currentExposure;
require(rescuableBalance >= amount, 'INSUFFICIENT_EXOGENOUS_ASSET_TO_RESCUE');
}
IERC20(token).safeTransfer(to, amount);
emit TokensRescued(token, to, amount);
}
/// @inheritdoc IGsm
function setSwapFreeze(bool enable) external onlyRole(SWAP_FREEZER_ROLE) {
if (enable) {
require(!_isFrozen, 'GSM_ALREADY_FROZEN');
} else {
require(_isFrozen, 'GSM_ALREADY_UNFROZEN');
}
_isFrozen = enable;
emit SwapFreeze(msg.sender, enable);
}
/// @inheritdoc IGsm
function seize() external notSeized onlyRole(LIQUIDATOR_ROLE) returns (uint256) {
_isSeized = true;
_currentExposure = 0;
_updateExposureCap(0);
(, uint256 ghoMinted) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(address(this));
uint256 underlyingBalance = IERC20(UNDERLYING_ASSET).balanceOf(address(this));
if (underlyingBalance > 0) {
IERC20(UNDERLYING_ASSET).safeTransfer(_ghoTreasury, underlyingBalance);
}
emit Seized(msg.sender, _ghoTreasury, underlyingBalance, ghoMinted);
return underlyingBalance;
}
/// @inheritdoc IGsm
function burnAfterSeize(uint256 amount) external onlyRole(LIQUIDATOR_ROLE) returns (uint256) {
require(_isSeized, 'GSM_NOT_SEIZED');
require(amount > 0, 'INVALID_AMOUNT');
(, uint256 ghoMinted) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(address(this));
if (amount > ghoMinted) {
amount = ghoMinted;
}
IGhoToken(GHO_TOKEN).transferFrom(msg.sender, address(this), amount);
IGhoToken(GHO_TOKEN).burn(amount);
emit BurnAfterSeize(msg.sender, amount, (ghoMinted - amount));
return amount;
}
/// @inheritdoc IGsm
function updateFeeStrategy(address feeStrategy) external onlyRole(CONFIGURATOR_ROLE) {
_updateFeeStrategy(feeStrategy);
}
/// @inheritdoc IGsm
function updateExposureCap(uint128 exposureCap) external onlyRole(CONFIGURATOR_ROLE) {
_updateExposureCap(exposureCap);
}
/// @inheritdoc IGhoFacilitator
function distributeFeesToTreasury() public virtual override {
uint256 accruedFees = _accruedFees;
if (accruedFees > 0) {
_accruedFees = 0;
IERC20(GHO_TOKEN).transfer(_ghoTreasury, accruedFees);
emit FeesDistributedToTreasury(_ghoTreasury, GHO_TOKEN, accruedFees);
}
}
/// @inheritdoc IGhoFacilitator
function updateGhoTreasury(address newGhoTreasury) external override onlyRole(CONFIGURATOR_ROLE) {
_updateGhoTreasury(newGhoTreasury);
}
/// @inheritdoc IGsm
function DOMAIN_SEPARATOR() external view returns (bytes32) {
return _domainSeparatorV4();
}
/// @inheritdoc IGsm
function getGhoAmountForBuyAsset(
uint256 minAssetAmount
) external view returns (uint256, uint256, uint256, uint256) {
return _calculateGhoAmountForBuyAsset(minAssetAmount);
}
/// @inheritdoc IGsm
function getGhoAmountForSellAsset(
uint256 maxAssetAmount
) external view returns (uint256, uint256, uint256, uint256) {
return _calculateGhoAmountForSellAsset(maxAssetAmount);
}
/// @inheritdoc IGsm
function getAssetAmountForBuyAsset(
uint256 maxGhoAmount
) external view returns (uint256, uint256, uint256, uint256) {
bool withFee = _feeStrategy != address(0);
uint256 grossAmount = withFee
? IGsmFeeStrategy(_feeStrategy).getGrossAmountFromTotalBought(maxGhoAmount)
: maxGhoAmount;
// round down so maxGhoAmount is guaranteed
uint256 assetAmount = IGsmPriceStrategy(PRICE_STRATEGY).getGhoPriceInAsset(grossAmount, false);
uint256 finalGrossAmount = IGsmPriceStrategy(PRICE_STRATEGY).getAssetPriceInGho(
assetAmount,
true
);
uint256 finalFee = withFee ? IGsmFeeStrategy(_feeStrategy).getBuyFee(finalGrossAmount) : 0;
return (assetAmount, finalGrossAmount + finalFee, finalGrossAmount, finalFee);
}
/// @inheritdoc IGsm
function getAssetAmountForSellAsset(
uint256 minGhoAmount
) external view returns (uint256, uint256, uint256, uint256) {
bool withFee = _feeStrategy != address(0);
uint256 grossAmount = withFee
? IGsmFeeStrategy(_feeStrategy).getGrossAmountFromTotalSold(minGhoAmount)
: minGhoAmount;
// round up so minGhoAmount is guaranteed
uint256 assetAmount = IGsmPriceStrategy(PRICE_STRATEGY).getGhoPriceInAsset(grossAmount, true);
uint256 finalGrossAmount = IGsmPriceStrategy(PRICE_STRATEGY).getAssetPriceInGho(
assetAmount,
false
);
uint256 finalFee = withFee ? IGsmFeeStrategy(_feeStrategy).getSellFee(finalGrossAmount) : 0;
return (assetAmount, finalGrossAmount - finalFee, finalGrossAmount, finalFee);
}
/// @inheritdoc IGsm
function getAvailableUnderlyingExposure() external view returns (uint256) {
return _exposureCap > _currentExposure ? _exposureCap - _currentExposure : 0;
}
/// @inheritdoc IGsm
function getExposureCap() external view returns (uint128) {
return _exposureCap;
}
/// @inheritdoc IGsm
function getAvailableLiquidity() external view returns (uint256) {
return _currentExposure;
}
/// @inheritdoc IGsm
function getFeeStrategy() external view returns (address) {
return _feeStrategy;
}
/// @inheritdoc IGsm
function getAccruedFees() external view returns (uint256) {
return _accruedFees;
}
/// @inheritdoc IGsm
function getIsFrozen() external view returns (bool) {
return _isFrozen;
}
/// @inheritdoc IGsm
function getIsSeized() external view returns (bool) {
return _isSeized;
}
/// @inheritdoc IGsm
function canSwap() external view returns (bool) {
return !_isFrozen && !_isSeized;
}
/// @inheritdoc IGhoFacilitator
function getGhoTreasury() external view override returns (address) {
return _ghoTreasury;
}
/// @inheritdoc IGsm
function GSM_REVISION() public pure virtual override returns (uint256) {
return 1;
}
/**
* @dev Buys an underlying asset with GHO
* @param originator The originator of the request
* @param minAmount The minimum amount of the underlying asset desired for purchase
* @param receiver The recipient address of the underlying asset being purchased
* @return The amount of underlying asset bought
* @return The amount of GHO sold by the user
*/
function _buyAsset(
address originator,
uint256 minAmount,
address receiver
) internal returns (uint256, uint256) {
(
uint256 assetAmount,
uint256 ghoSold,
uint256 grossAmount,
uint256 fee
) = _calculateGhoAmountForBuyAsset(minAmount);
_beforeBuyAsset(originator, assetAmount, receiver);
require(assetAmount > 0, 'INVALID_AMOUNT');
require(_currentExposure >= assetAmount, 'INSUFFICIENT_AVAILABLE_EXOGENOUS_ASSET_LIQUIDITY');
_currentExposure -= uint128(assetAmount);
_accruedFees += fee.toUint128();
IGhoToken(GHO_TOKEN).transferFrom(originator, address(this), ghoSold);
IGhoToken(GHO_TOKEN).burn(grossAmount);
IERC20(UNDERLYING_ASSET).safeTransfer(receiver, assetAmount);
emit BuyAsset(originator, receiver, assetAmount, ghoSold, fee);
return (assetAmount, ghoSold);
}
/**
* @dev Hook that is called before `buyAsset`.
* @dev This can be used to add custom logic
* @param originator Originator of the request
* @param amount The amount of the underlying asset desired for purchase
* @param receiver Recipient address of the underlying asset being purchased
*/
function _beforeBuyAsset(address originator, uint256 amount, address receiver) internal virtual {}
/**
* @dev Sells an underlying asset for GHO
* @param originator The originator of the request
* @param maxAmount The maximum amount of the underlying asset desired to sell
* @param receiver The recipient address of the GHO being purchased
* @return The amount of underlying asset sold
* @return The amount of GHO bought by the user
*/
function _sellAsset(
address originator,
uint256 maxAmount,
address receiver
) internal returns (uint256, uint256) {
(
uint256 assetAmount,
uint256 ghoBought,
uint256 grossAmount,
uint256 fee
) = _calculateGhoAmountForSellAsset(maxAmount);
_beforeSellAsset(originator, assetAmount, receiver);
require(assetAmount > 0, 'INVALID_AMOUNT');
require(_currentExposure + assetAmount <= _exposureCap, 'EXOGENOUS_ASSET_EXPOSURE_TOO_HIGH');
_currentExposure += uint128(assetAmount);
_accruedFees += fee.toUint128();
IERC20(UNDERLYING_ASSET).safeTransferFrom(originator, address(this), assetAmount);
IGhoToken(GHO_TOKEN).mint(address(this), grossAmount);
IGhoToken(GHO_TOKEN).transfer(receiver, ghoBought);
emit SellAsset(originator, receiver, assetAmount, grossAmount, fee);
return (assetAmount, ghoBought);
}
/**
* @dev Hook that is called before `sellAsset`.
* @dev This can be used to add custom logic
* @param originator Originator of the request
* @param amount The amount of the underlying asset desired to sell
* @param receiver Recipient address of the GHO being purchased
*/
function _beforeSellAsset(
address originator,
uint256 amount,
address receiver
) internal virtual {}
/**
* @dev Returns the amount of GHO sold in exchange of buying underlying asset
* @param assetAmount The amount of underlying asset to buy
* @return The exact amount of asset the user purchases
* @return The total amount of GHO the user sells (gross amount in GHO plus fee)
* @return The gross amount of GHO
* @return The fee amount in GHO, applied on top of gross amount of GHO
*/
function _calculateGhoAmountForBuyAsset(
uint256 assetAmount
) internal view returns (uint256, uint256, uint256, uint256) {
bool withFee = _feeStrategy != address(0);
// pick the highest GHO amount possible for given asset amount
uint256 grossAmount = IGsmPriceStrategy(PRICE_STRATEGY).getAssetPriceInGho(assetAmount, true);
uint256 fee = withFee ? IGsmFeeStrategy(_feeStrategy).getBuyFee(grossAmount) : 0;
uint256 ghoSold = grossAmount + fee;
uint256 finalGrossAmount = withFee
? IGsmFeeStrategy(_feeStrategy).getGrossAmountFromTotalBought(ghoSold)
: ghoSold;
// pick the lowest asset amount possible for given GHO amount
uint256 finalAssetAmount = IGsmPriceStrategy(PRICE_STRATEGY).getGhoPriceInAsset(
finalGrossAmount,
false
);
uint256 finalFee = ghoSold - finalGrossAmount;
return (finalAssetAmount, finalGrossAmount + finalFee, finalGrossAmount, finalFee);
}
/**
* @dev Returns the amount of GHO bought in exchange of a given amount of underlying asset
* @param assetAmount The amount of underlying asset to sell
* @return The exact amount of asset the user sells
* @return The total amount of GHO the user buys (gross amount in GHO minus fee)
* @return The gross amount of GHO
* @return The fee amount in GHO, applied to the gross amount of GHO
*/
function _calculateGhoAmountForSellAsset(
uint256 assetAmount
) internal view returns (uint256, uint256, uint256, uint256) {
bool withFee = _feeStrategy != address(0);
// pick the lowest GHO amount possible for given asset amount
uint256 grossAmount = IGsmPriceStrategy(PRICE_STRATEGY).getAssetPriceInGho(assetAmount, false);
uint256 fee = withFee ? IGsmFeeStrategy(_feeStrategy).getSellFee(grossAmount) : 0;
uint256 ghoBought = grossAmount - fee;
uint256 finalGrossAmount = withFee
? IGsmFeeStrategy(_feeStrategy).getGrossAmountFromTotalSold(ghoBought)
: ghoBought;
// pick the highest asset amount possible for given GHO amount
uint256 finalAssetAmount = IGsmPriceStrategy(PRICE_STRATEGY).getGhoPriceInAsset(
finalGrossAmount,
true
);
uint256 finalFee = finalGrossAmount - ghoBought;
return (finalAssetAmount, finalGrossAmount - finalFee, finalGrossAmount, finalFee);
}
/**
* @dev Updates Fee Strategy
* @param feeStrategy The address of the new Fee Strategy
*/
function _updateFeeStrategy(address feeStrategy) internal {
address oldFeeStrategy = _feeStrategy;
_feeStrategy = feeStrategy;
emit FeeStrategyUpdated(oldFeeStrategy, feeStrategy);
}
/**
* @dev Updates Exposure Cap
* @param exposureCap The value of the new Exposure Cap
*/
function _updateExposureCap(uint128 exposureCap) internal {
uint128 oldExposureCap = _exposureCap;
_exposureCap = exposureCap;
emit ExposureCapUpdated(oldExposureCap, exposureCap);
}
/**
* @dev Updates GHO Treasury Address
* @param newGhoTreasury The address of the new GHO Treasury
*/
function _updateGhoTreasury(address newGhoTreasury) internal {
require(newGhoTreasury != address(0), 'ZERO_ADDRESS_NOT_VALID');
address oldGhoTreasury = _ghoTreasury;
_ghoTreasury = newGhoTreasury;
emit GhoTreasuryUpdated(oldGhoTreasury, newGhoTreasury);
}
/// @inheritdoc VersionedInitializable
function getRevision() internal pure virtual override returns (uint256) {
return GSM_REVISION();
}
}
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
IAccessControl.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
IGsm.sol 372 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IAccessControl} from '@openzeppelin/contracts/access/IAccessControl.sol';
import {IGhoFacilitator} from '../../../gho/interfaces/IGhoFacilitator.sol';
/**
* @title IGsm
* @author Aave
* @notice Defines the behaviour of a GHO Stability Module
*/
interface IGsm is IAccessControl, IGhoFacilitator {
/**
* @dev Emitted when a user buys an asset (selling GHO) in the GSM
* @param originator The address of the buyer originating the request
* @param receiver The address of the receiver of the underlying asset
* @param underlyingAmount The amount of the underlying asset bought
* @param ghoAmount The amount of GHO sold, inclusive of fee
* @param fee The fee paid by the buyer, in GHO
*/
event BuyAsset(
address indexed originator,
address indexed receiver,
uint256 underlyingAmount,
uint256 ghoAmount,
uint256 fee
);
/**
* @dev Emitted when a user sells an asset (buying GHO) in the GSM
* @param originator The address of the seller originating the request
* @param receiver The address of the receiver of GHO
* @param underlyingAmount The amount of the underlying asset sold
* @param ghoAmount The amount of GHO bought, inclusive of fee
* @param fee The fee paid by the buyer, in GHO
*/
event SellAsset(
address indexed originator,
address indexed receiver,
uint256 underlyingAmount,
uint256 ghoAmount,
uint256 fee
);
/**
* @dev Emitted when the Swap Freezer freezes buys/sells
* @param freezer The address of the Swap Freezer
* @param enabled True if swap functions are frozen, False otherwise
*/
event SwapFreeze(address indexed freezer, bool enabled);
/**
* @dev Emitted when a Liquidator seizes GSM funds
* @param seizer The address originating the seizure request
* @param recipient The address of the recipient of seized funds
* @param underlyingAmount The amount of the underlying asset seized
* @param ghoOutstanding The amount of remaining GHO that the GSM had minted
*/
event Seized(
address indexed seizer,
address indexed recipient,
uint256 underlyingAmount,
uint256 ghoOutstanding
);
/**
* @dev Emitted when burning GHO after a seizure of GSM funds
* @param burner The address of the burner
* @param amount The amount of GHO burned
* @param ghoOutstanding The amount of remaining GHO that the GSM had minted
*/
event BurnAfterSeize(address indexed burner, uint256 amount, uint256 ghoOutstanding);
/**
* @dev Emitted when the Fee Strategy is updated
* @param oldFeeStrategy The address of the old Fee Strategy
* @param newFeeStrategy The address of the new Fee Strategy
*/
event FeeStrategyUpdated(address indexed oldFeeStrategy, address indexed newFeeStrategy);
/**
* @dev Emitted when the GSM underlying asset Exposure Cap is updated
* @param oldExposureCap The amount of the old Exposure Cap
* @param newExposureCap The amount of the new Exposure Cap
*/
event ExposureCapUpdated(uint256 oldExposureCap, uint256 newExposureCap);
/**
* @dev Emitted when tokens are rescued from the GSM
* @param tokenRescued The address of the rescued token
* @param recipient The address that received the rescued tokens
* @param amountRescued The amount of token rescued
*/
event TokensRescued(
address indexed tokenRescued,
address indexed recipient,
uint256 amountRescued
);
/**
* @notice Buys the GSM underlying asset in exchange for selling GHO
* @dev Use `getAssetAmountForBuyAsset` function to calculate the amount based on the GHO amount to sell
* @param minAmount The minimum amount of the underlying asset to buy
* @param receiver Recipient address of the underlying asset being purchased
* @return The amount of underlying asset bought
* @return The amount of GHO sold by the user
*/
function buyAsset(uint256 minAmount, address receiver) external returns (uint256, uint256);
/**
* @notice Buys the GSM underlying asset in exchange for selling GHO, using an EIP-712 signature
* @dev Use `getAssetAmountForBuyAsset` function to calculate the amount based on the GHO amount to sell
* @param originator The signer of the request
* @param minAmount The minimum amount of the underlying asset to buy
* @param receiver Recipient address of the underlying asset being purchased
* @param deadline Signature expiration deadline
* @param signature Signature data
* @return The amount of underlying asset bought
* @return The amount of GHO sold by the user
*/
function buyAssetWithSig(
address originator,
uint256 minAmount,
address receiver,
uint256 deadline,
bytes calldata signature
) external returns (uint256, uint256);
/**
* @notice Sells the GSM underlying asset in exchange for buying GHO
* @dev Use `getAssetAmountForSellAsset` function to calculate the amount based on the GHO amount to buy
* @param maxAmount The maximum amount of the underlying asset to sell
* @param receiver Recipient address of the GHO being purchased
* @return The amount of underlying asset sold
* @return The amount of GHO bought by the user
*/
function sellAsset(uint256 maxAmount, address receiver) external returns (uint256, uint256);
/**
* @notice Sells the GSM underlying asset in exchange for buying GHO, using an EIP-712 signature
* @dev Use `getAssetAmountForSellAsset` function to calculate the amount based on the GHO amount to buy
* @param originator The signer of the request
* @param maxAmount The maximum amount of the underlying asset to sell
* @param receiver Recipient address of the GHO being purchased
* @param deadline Signature expiration deadline
* @param signature Signature data
* @return The amount of underlying asset sold
* @return The amount of GHO bought by the user
*/
function sellAssetWithSig(
address originator,
uint256 maxAmount,
address receiver,
uint256 deadline,
bytes calldata signature
) external returns (uint256, uint256);
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function rescueTokens(address token, address to, uint256 amount) external;
/**
* @notice Enable or disable the swap freeze
* @param enable True to freeze swap functions, false otherwise
*/
function setSwapFreeze(bool enable) external;
/**
* @notice Seizes all of the underlying asset from the GSM, sending to the Treasury
* @dev Seizing is a last resort mechanism to provide the Treasury with the entire amount of underlying asset
* so it can be used to backstop any potential event impacting the functionality of the Gsm.
* @dev Seizing disables the swap feature
* @return The amount of underlying asset seized and transferred to Treasury
*/
function seize() external returns (uint256);
/**
* @notice Burns an amount of GHO after seizure reducing the facilitator bucket level effectively
* @dev Passing an amount higher than the facilitator bucket level will result in burning all minted GHO
* @dev Only callable if the GSM has assets seized, helpful to wind down the facilitator
* @param amount The amount of GHO to burn
* @return The amount of GHO burned
*/
function burnAfterSeize(uint256 amount) external returns (uint256);
/**
* @notice Updates the address of the Fee Strategy
* @param feeStrategy The address of the new FeeStrategy
*/
function updateFeeStrategy(address feeStrategy) external;
/**
* @notice Updates the exposure cap of the underlying asset
* @param exposureCap The new value for the exposure cap (in underlying asset terms)
*/
function updateExposureCap(uint128 exposureCap) external;
/**
* @notice Returns the EIP712 domain separator
* @return The EIP712 domain separator
*/
function DOMAIN_SEPARATOR() external view returns (bytes32);
/**
* @notice Returns the total amount of GHO, gross amount and fee result of buying assets
* @param minAssetAmount The minimum amount of underlying asset to buy
* @return The exact amount of underlying asset to be bought
* @return The total amount of GHO the user sells (gross amount in GHO plus fee)
* @return The gross amount of GHO
* @return The fee amount in GHO, applied on top of gross amount of GHO
*/
function getGhoAmountForBuyAsset(
uint256 minAssetAmount
) external view returns (uint256, uint256, uint256, uint256);
/**
* @notice Returns the total amount of GHO, gross amount and fee result of selling assets
* @param maxAssetAmount The maximum amount of underlying asset to sell
* @return The exact amount of underlying asset to sell
* @return The total amount of GHO the user buys (gross amount in GHO minus fee)
* @return The gross amount of GHO
* @return The fee amount in GHO, applied to the gross amount of GHO
*/
function getGhoAmountForSellAsset(
uint256 maxAssetAmount
) external view returns (uint256, uint256, uint256, uint256);
/**
* @notice Returns the amount of underlying asset, gross amount of GHO and fee result of buying assets
* @param maxGhoAmount The maximum amount of GHO the user provides for buying underlying asset
* @return The amount of underlying asset the user buys
* @return The exact amount of GHO the user provides
* @return The gross amount of GHO corresponding to the given total amount of GHO
* @return The fee amount in GHO, charged for buying assets
*/
function getAssetAmountForBuyAsset(
uint256 maxGhoAmount
) external view returns (uint256, uint256, uint256, uint256);
/**
* @notice Returns the amount of underlying asset, gross amount of GHO and fee result of selling assets
* @param minGhoAmount The minimum amount of GHO the user must receive for selling underlying asset
* @return The amount of underlying asset the user sells
* @return The exact amount of GHO the user receives in exchange
* @return The gross amount of GHO corresponding to the given total amount of GHO
* @return The fee amount in GHO, charged for selling assets
*/
function getAssetAmountForSellAsset(
uint256 minGhoAmount
) external view returns (uint256, uint256, uint256, uint256);
/**
* @notice Returns the remaining GSM exposure capacity
* @return The amount of underlying asset that can be sold to the GSM
*/
function getAvailableUnderlyingExposure() external view returns (uint256);
/**
* @notice Returns the exposure limit to the underlying asset
* @return The maximum amount of underlying asset that can be sold to the GSM
*/
function getExposureCap() external view returns (uint128);
/**
* @notice Returns the actual underlying asset balance immediately available in the GSM
* @return The amount of underlying asset that can be bought from the GSM
*/
function getAvailableLiquidity() external view returns (uint256);
/**
* @notice Returns the Fee Strategy for the GSM
* @dev It returns 0x0 in case of no fee strategy
* @return The address of the FeeStrategy
*/
function getFeeStrategy() external view returns (address);
/**
* @notice Returns the amount of current accrued fees
* @dev It does not factor in potential fees that can be accrued upon distribution of fees
* @return The amount of accrued fees
*/
function getAccruedFees() external view returns (uint256);
/**
* @notice Returns the freeze status of the GSM
* @return True if frozen, false if not
*/
function getIsFrozen() external view returns (bool);
/**
* @notice Returns the current seizure status of the GSM
* @return True if the GSM has been seized, false if not
*/
function getIsSeized() external view returns (bool);
/**
* @notice Returns whether or not swaps via buyAsset/sellAsset are currently possible
* @return True if the GSM has swapping enabled, false otherwise
*/
function canSwap() external view returns (bool);
/**
* @notice Returns the GSM revision number
* @return The revision number
*/
function GSM_REVISION() external pure returns (uint256);
/**
* @notice Returns the address of the GHO token
* @return The address of GHO token contract
*/
function GHO_TOKEN() external view returns (address);
/**
* @notice Returns the underlying asset of the GSM
* @return The address of the underlying asset
*/
function UNDERLYING_ASSET() external view returns (address);
/**
* @notice Returns the price strategy of the GSM
* @return The address of the price strategy
*/
function PRICE_STRATEGY() external view returns (address);
/**
* @notice Returns the current nonce (for EIP-712 signature methods) of an address
* @param user The address of the user
* @return The current nonce of the user
*/
function nonces(address user) external view returns (uint256);
/**
* @notice Returns the identifier of the Configurator Role
* @return The bytes32 id hash of the Configurator role
*/
function CONFIGURATOR_ROLE() external pure returns (bytes32);
/**
* @notice Returns the identifier of the Token Rescuer Role
* @return The bytes32 id hash of the TokenRescuer role
*/
function TOKEN_RESCUER_ROLE() external pure returns (bytes32);
/**
* @notice Returns the identifier of the Swap Freezer Role
* @return The bytes32 id hash of the SwapFreezer role
*/
function SWAP_FREEZER_ROLE() external pure returns (bytes32);
/**
* @notice Returns the identifier of the Liquidator Role
* @return The bytes32 id hash of the Liquidator role
*/
function LIQUIDATOR_ROLE() external pure returns (bytes32);
/**
* @notice Returns the EIP-712 signature typehash for buyAssetWithSig
* @return The bytes32 signature typehash for buyAssetWithSig
*/
function BUY_ASSET_WITH_SIG_TYPEHASH() external pure returns (bytes32);
/**
* @notice Returns the EIP-712 signature typehash for sellAssetWithSig
* @return The bytes32 signature typehash for sellAssetWithSig
*/
function SELL_ASSET_WITH_SIG_TYPEHASH() external pure returns (bytes32);
}
VersionedInitializable.sol 77 lines
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.10;
/**
* @title VersionedInitializable
* @author Aave, inspired by the OpenZeppelin Initializable contract
* @notice Helper contract to implement initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* @dev WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*/
abstract contract VersionedInitializable {
/**
* @dev Indicates that the contract has been initialized.
*/
uint256 private lastInitializedRevision = 0;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
uint256 revision = getRevision();
require(
initializing || isConstructor() || revision > lastInitializedRevision,
'Contract instance has already been initialized'
);
bool isTopLevelCall = !initializing;
if (isTopLevelCall) {
initializing = true;
lastInitializedRevision = revision;
}
_;
if (isTopLevelCall) {
initializing = false;
}
}
/**
* @notice Returns the revision number of the contract
* @dev Needs to be defined in the inherited class as a constant.
* @return The revision number
*/
function getRevision() internal pure virtual returns (uint256);
/**
* @notice Returns true if and only if the function is running in the constructor
* @return True if the function is running in the constructor
*/
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
//solium-disable-next-line
assembly {
cs := extcodesize(address())
}
return cs == 0;
}
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
EIP712.sol 104 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
/**
* @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
*
* The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
* thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
* they need in their contracts using a combination of `abi.encode` and `keccak256`.
*
* This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
* scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
* ({_hashTypedDataV4}).
*
* The implementation of the domain separator was designed to be as efficient as possible while still properly updating
* the chain id to protect against replay attacks on an eventual fork of the chain.
*
* NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
* https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
*
* _Available since v3.4._
*/
abstract contract EIP712 {
/* solhint-disable var-name-mixedcase */
// Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
// invalidate the cached domain separator if the chain id changes.
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
/* solhint-enable var-name-mixedcase */
/**
* @dev Initializes the domain separator and parameter caches.
*
* The meaning of `name` and `version` is specified in
* https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
*
* - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
* - `version`: the current major version of the signing domain.
*
* NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
* contract upgrade].
*/
constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS = address(this);
_TYPE_HASH = typeHash;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
/**
* @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
* function returns the hash of the fully encoded EIP712 message for this domain.
*
* This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
*
* ```solidity
* bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
* keccak256("Mail(address to,string contents)"),
* mailTo,
* keccak256(bytes(mailContents))
* )));
* address signer = ECDSA.recover(digest, signature);
* ```
*/
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
SignatureChecker.sol 42 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
import "../Address.sol";
import "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
if (error == ECDSA.RecoverError.NoError && recovered == signer) {
return true;
}
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length == 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}
AccessControl.sol 247 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
IGsmFeeStrategy.sol 40 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IGsmFeeStrategy
* @author Aave
* @notice Defines the behaviour of Fee Strategies
* @dev Functions' logic must be invertible, being possible to calculate the fee amount based on the gross amount, and
* the other way round.
* @dev All math operations must round up, favoring the protocol.
*/
interface IGsmFeeStrategy {
/**
* @notice Returns the fee to be applied when buying an underlying asset in exchange for GHO
* @param grossAmount The amount of GHO being sold for the underlying asset
* @return The fee amount of GHO
*/
function getBuyFee(uint256 grossAmount) external view returns (uint256);
/**
* @notice Returns the fee to be applied when buying GHO in exchange for an underlying asset
* @param grossAmount The amount of underlying, converted to GHO, being sold
* @return The fee amount of GHO
*/
function getSellFee(uint256 grossAmount) external view returns (uint256);
/**
* @notice Returns the gross amount of GHO being bought based on the total bought amount
* @param totalAmount The total amount of GHO being bought (gross amount, GHO bought plus fee)
* @return The gross amount of GHO being bought (total amount minus fee)
*/
function getGrossAmountFromTotalBought(uint256 totalAmount) external view returns (uint256);
/**
* @notice Returns the amount of GHO being sold based on the total sold amount
* @param totalAmount The total amount of GHO being sold (gross amount, GHO sold minus fee)
* @return The gross amount of GHO being sold (total amount plus fee)
*/
function getGrossAmountFromTotalSold(uint256 totalAmount) external view returns (uint256);
}
ECDSA.sol 213 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
IERC1271.sol 19 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}
Strings.sol 70 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
ERC165.sol 29 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 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);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
Math.sol 345 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return 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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev 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 {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// 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(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// 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].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
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 for
// four bits. That is, denominator * inv = 1 mod 2^4.
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^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // 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 preconditions 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 * inverse;
return result;
}
}
/**
* @notice 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) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
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 log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* 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[EIP 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);
}
Read Contract
BUY_ASSET_WITH_SIG_TYPEHASH 0x8a96e304 → bytes32
CONFIGURATOR_ROLE 0xd853015e → bytes32
DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
DOMAIN_SEPARATOR 0x3644e515 → bytes32
GHO_TOKEN 0xb1c660f7 → address
GSM_REVISION 0x78cf12b2 → uint256
LIQUIDATOR_ROLE 0x16d8887a → bytes32
PRICE_STRATEGY 0xab16b58a → address
SELL_ASSET_WITH_SIG_TYPEHASH 0x6400a4af → bytes32
SWAP_FREEZER_ROLE 0x353f03bd → bytes32
TOKEN_RESCUER_ROLE 0x8bcd9797 → bytes32
UNDERLYING_ASSET 0xe6025393 → address
canSwap 0x10ce0516 → bool
getAccruedFees 0x1f3da150 → uint256
getAssetAmountForBuyAsset 0xaa278b03 → uint256, uint256, uint256, uint256
getAssetAmountForSellAsset 0xa9c3ebda → uint256, uint256, uint256, uint256
getAvailableLiquidity 0x9b745aec → uint256
getAvailableUnderlyingExposure 0x110934d6 → uint256
getCurrentBacking 0x476cce03 → uint256, uint256
getExposureCap 0x8fa46890 → uint128
getFeeStrategy 0x4101d9f4 → address
getGhoAmountForBuyAsset 0xcea46213 → uint256, uint256, uint256, uint256
getGhoAmountForSellAsset 0xc431280e → uint256, uint256, uint256, uint256
getGhoTreasury 0xe28178cc → address
getIsFrozen 0x236fc8ad → bool
getIsSeized 0x80bc659a → bool
getRoleAdmin 0x248a9ca3 → bytes32
hasRole 0x91d14854 → bool
nonces 0x7ecebe00 → uint256
supportsInterface 0x01ffc9a7 → bool
Write Contract 18 functions
These functions modify contract state and require a wallet transaction to execute.
backWithGho 0x9b5c9261
uint256 amount
returns: uint256
backWithUnderlying 0xc350de6c
uint256 amount
returns: uint256
burnAfterSeize 0x5921c8e0
uint256 amount
returns: uint256
buyAsset 0x40fb07a0
uint256 minAmount
address receiver
returns: uint256, uint256
buyAssetWithSig 0x954c1c0d
address originator
uint256 minAmount
address receiver
uint256 deadline
bytes signature
returns: uint256, uint256
distributeFeesToTreasury 0xdc49a07b
No parameters
grantRole 0x2f2ff15d
bytes32 role
address account
initialize 0x7265580f
address admin
address ghoTreasury
uint128 exposureCap
renounceRole 0x36568abe
bytes32 role
address account
rescueTokens 0xcea9d26f
address token
address to
uint256 amount
revokeRole 0xd547741f
bytes32 role
address account
seize 0x605297e1
No parameters
returns: uint256
sellAsset 0xaa443ac0
uint256 maxAmount
address receiver
returns: uint256, uint256
sellAssetWithSig 0xf493ca70
address originator
uint256 maxAmount
address receiver
uint256 deadline
bytes signature
returns: uint256, uint256
setSwapFreeze 0xcab46bc6
bool enable
updateExposureCap 0x430b0952
uint128 exposureCap
updateFeeStrategy 0xc876a2a7
address feeStrategy
updateGhoTreasury 0x1fde40bb
address newGhoTreasury
Recent Transactions
This address has 1 on-chain transactions, but only 1.6% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →