Address Contract Verified
Address
0xD63106f742EF0DE4d4F209F59D3c31b63EB58ced
Balance
0 ETH
Nonce
1
Code Size
13642 bytes
Creator
0x10163f09...9203 at tx 0x76e2913c...81c4a8
Indexed Transactions
0
Contract Bytecode
13642 bytes
0x6080604052600436106102cc5760003560e01c80636afc0c5f1161017557806398ea5fca116100dc578063b2d8cd4b11610095578063b78b52df1161006f578063b78b52df146108b9578063bcd135af146108d9578063dd62ed3e146108f9578063f2e68dd11461093f57600080fd5b8063b2d8cd4b14610859578063b352fffe14610879578063b3eb2c661461089957600080fd5b806398ea5fca146107be5780639dc29fac146107c6578063a8fa343c146107e6578063a9059cbb14610806578063abbb96ea14610826578063b0f43e5f1461083957600080fd5b80638c61caff1161012e5780638c61caff146107185780638da5cb5b146107385780638fd6a6ac146107565780639358928b1461077457806395d89b411461078957806396d3b83d1461079e57600080fd5b80636afc0c5f146106775780636c89be01146106995780636c98faab146106ae57806370a08231146106c357806379cc6790146106e35780638401b9681461070357600080fd5b8063313ce5671161023457806352820bb3116101ed57806362d6a806116101c757806362d6a806146105e8578063648a54551461062157806369bb4dc21461064157806369dcf9e11461065657600080fd5b806352820bb3146105885780635417efff146105a85780635d3143fa146105c857600080fd5b8063313ce567146104dc578063355274ea146104fe57806340c10f191461051357806342966c6814610533578063487f24ae146105535780634b3271aa1461056857600080fd5b80631f520cd2116102865780631f520cd2146103f057806321842be31461042f57806323b872dd1461044457806326947d2b1461046457806329be2f8a1461049c5780632af4c31e146104bc57600080fd5b8062d3794e1461031357806306fdde0314610335578063095ea7b3146103605780630f4dd5241461039057806318160ddd146103b157806319d5fef8146103d057600080fd5b3661030e57604080513481526000602082015233917f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca910160405180910390a2005b600080fd5b34801561031f57600080fd5b5061033361032e366004612c93565b61097e565b005b34801561034157600080fd5b5061034a610a9c565b6040516103579190612cec565b60405180910390f35b34801561036c57600080fd5b5061038061037b366004612d1f565b610b2e565b6040519015158152602001610357565b34801561039c57600080fd5b50600e5461038090600160a01b900460ff1681565b3480156103bd57600080fd5b506002545b604051908152602001610357565b3480156103dc57600080fd5b506103336103eb366004612e21565b610b48565b3480156103fc57600080fd5b5061041061040b366004612eea565b610c01565b6040805192151583526001600160401b03909116602083015201610357565b34801561043b57600080fd5b50610333610c78565b34801561045057600080fd5b5061038061045f366004612f07565b610cb1565b34801561047057600080fd5b5061048461047f366004612f48565b610da0565b6040516001600160a01b039091168152602001610357565b3480156104a857600080fd5b506103336104b7366004612f78565b610dca565b3480156104c857600080fd5b506103336104d7366004612eea565b610e32565b3480156104e857600080fd5b5060075460405160ff9091168152602001610357565b34801561050a57600080fd5b506006546103c2565b34801561051f57600080fd5b5061033361052e366004612d1f565b610eb9565b34801561053f57600080fd5b5061033361054e366004612f48565b610fac565b34801561055f57600080fd5b50610333611046565b34801561057457600080fd5b50610333610583366004612fb4565b61107f565b34801561059457600080fd5b506103336105a3366004612eea565b6110da565b3480156105b457600080fd5b506103336105c336600461301c565b611160565b3480156105d457600080fd5b506103336105e33660046130b4565b6111b1565b3480156105f457600080fd5b50610380610603366004612f78565b6001600160401b03166000908152600c602052604090205460ff1690565b34801561062d57600080fd5b5061033361063c3660046130eb565b6114a2565b34801561064d57600080fd5b506008546103c2565b34801561066257600080fd5b50600e5461038090600160a81b900460ff1681565b34801561068357600080fd5b5061068c611704565b6040516103579190613130565b3480156106a557600080fd5b506103c2611765565b3480156106ba57600080fd5b506103336117a7565b3480156106cf57600080fd5b506103c26106de366004612eea565b6117e0565b3480156106ef57600080fd5b506103336106fe366004612d1f565b6117fb565b34801561070f57600080fd5b506103c2611847565b34801561072457600080fd5b506103c2610733366004612eea565b611858565b34801561074457600080fd5b506005546001600160a01b0316610484565b34801561076257600080fd5b50600d546001600160a01b0316610484565b34801561078057600080fd5b506103c2611955565b34801561079557600080fd5b5061034a611972565b3480156107aa57600080fd5b506103336107b936600461318a565b611981565b6103c26119d6565b3480156107d257600080fd5b506103336107e1366004612d1f565b611bc7565b3480156107f257600080fd5b50610333610801366004612eea565b611bea565b34801561081257600080fd5b50610380610821366004612d1f565b611c70565b34801561083257600080fd5b50476103c2565b34801561084557600080fd5b506103336108543660046131b6565b611d52565b34801561086557600080fd5b50610333610874366004612f48565b611e05565b34801561088557600080fd5b506103336108943660046131e2565b611eab565b3480156108a557600080fd5b506103336108b4366004613200565b611f35565b3480156108c557600080fd5b506103336108d4366004612d1f565b61212a565b3480156108e557600080fd5b506103336108f4366004612f78565b612215565b34801561090557600080fd5b506103c261091436600461321b565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b34801561094b57600080fd5b50600e5461096690600160b01b90046001600160401b031681565b6040516001600160401b039091168152602001610357565b600e546001600160a01b031633146109b15760405162461bcd60e51b81526004016109a890613239565b60405180910390fd5b60128160ff1611156109ee5760405162461bcd60e51b81526004016109a8906020808252600490820152634531303560e01b604082015260600190565b6001600160a01b0382166000908152600f602052604090205460ff16610a98576001600160a01b0382166000818152600f602090815260408083208054600160ff199182168117909255601184528285208054821690556012805492830190557fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344490910180546001600160a01b03191690951790945560139091529020805490911660ff83161790555b5050565b606060038054610aab90613255565b80601f0160208091040260200160405190810160405280929190818152602001828054610ad790613255565b8015610b245780601f10610af957610100808354040283529160200191610b24565b820191906000526020600020905b815481529060010190602001808311610b0757829003601f168201915b5050505050905090565b600033610b3c81858561227e565b60019150505b92915050565b6005546001600160a01b03163314610b725760405162461bcd60e51b81526004016109a890613289565b8051825114610bac5760405162461bcd60e51b81526004016109a890602080825260049082015263114c4c0d60e21b604082015260600190565b60005b8251811015610bfc57610bf4838281518110610bcd57610bcd6132a7565b6020026020010151838381518110610be757610be76132a7565b602002602001015161212a565b600101610baf565b505050565b6001600160a01b0381166000908152600f60205260408120548190839060ff16610c3d5760405162461bcd60e51b81526004016109a8906132bd565b5050506001600160a01b031660009081526011602090815260408083205460109092529091205460ff909116916001600160401b0390911690565b6005546001600160a01b03163314610ca25760405162461bcd60e51b81526004016109a890613289565b600b805460ff19166001179055565b600b5460009060ff16610cef5760405162461bcd60e51b8152602060048201526006602482015265131bd8dad95960d21b60448201526064016109a8565b6001600160a01b038416610d1957604051634b637e8f60e11b8152600060048201526024016109a8565b6001600160a01b038316610d435760405163ec442f0560e01b8152600060048201526024016109a8565b6000610d4f858461228b565b905082811015610d8a5760405162461bcd60e51b81526004016109a8906020808252600490820152632298981960e11b604082015260600190565b610d958585856123c0565b9150505b9392505050565b60128181548110610db057600080fd5b6000918252602090912001546001600160a01b0316905081565b600e546001600160a01b03163314610df45760405162461bcd60e51b81526004016109a890613239565b600e805460ff60a81b196001600160401b03909316600160b01b029290921668ffffffffffffffffff60a81b1990921691909117600160a81b179055565b6005546001600160a01b03163314610e5c5760405162461bcd60e51b81526004016109a890613289565b600580546001600160a01b0319166001600160a01b03831690811790915560408051338152602081019290925242917f079a159bc2c4ed6aaee92c293d83b6527a380c127aca07f41d3ab4c590957f56910160405180910390a250565b600d546001600160a01b03163314610efc5760405162461bcd60e51b815260206004820152600660248201526511195b9a595960d21b60448201526064016109a8565b60065481610f0960025490565b610f1391906132ef565b1115610f415760025460065460405163279e7e1560e21b8152600481019290925260248201526044016109a8565b610f4b82826123e4565b610f53611955565b600254610f609190613302565b600855600d546040518281526001600160a01b03918216918416907f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f09060200160405180910390a35050565b6005546001600160a01b0316330361100657600854811115610ff55760405162461bcd60e51b8152602060048201526002602482015261453160f01b60448201526064016109a8565b61100130600083612416565b611010565b611010338261243e565b6040518181527f4cd1cedac1faabaf2d2d626f6caa6a7df4cf69ec7ecc3bcae2f938bdedc860719060200160405180910390a150565b600e546001600160a01b031633146110705760405162461bcd60e51b81526004016109a890613239565b600e805460ff60a81b19169055565b6005546001600160a01b031633146110a95760405162461bcd60e51b81526004016109a890613289565b6110b3868661212a565b60648360ff1611156110c457606492505b6110d286848685858a612474565b505050505050565b600e546001600160a01b031633146111045760405162461bcd60e51b81526004016109a890613239565b6001600160a01b0381166000908152600f6020526040902054819060ff1661113e5760405162461bcd60e51b81526004016109a8906132bd565b506001600160a01b03166000908152601160205260409020805460ff19169055565b6005546001600160a01b0316331461118a5760405162461bcd60e51b81526004016109a890613289565b60006111974287876126aa565b90506111a788888387878761107f565b5050505050505050565b6001600160a01b0381166000908152600f6020526040902054819060ff1680156111f357506001600160a01b03811660009081526011602052604090205460ff165b801561121f57506001600160a01b0381166000908152601060205260409020546001600160401b031615155b6112505760405162461bcd60e51b8152602060048201526002602482015261114d60f21b60448201526064016109a8565b826001600160801b0316611263336117e0565b10156112905733611273336117e0565b8460405163391434e360e21b81526004016109a893929190613315565b6001600160a01b0382166000908152601360205260408120546112b79060ff16601261333f565b6001600160a01b038416600090815260106020526040812054600e549293506001600160801b038716926001600160401b039091169061130290600160f01b900461ffff1684613358565b61130c919061336f565b905060ff83161561132f5761132283600a613478565b61132c908261336f565b90505b600061133a86611858565b90508082111561139257600e546001600160a01b0387166000908152601060205260409020549192508291600160f01b90910461ffff1690611385906001600160401b031683613358565b61138f919061336f565b96505b60405163a9059cbb60e01b8152336004820152602481018390526001600160a01b0387169063a9059cbb906044016020604051808303816000875af11580156113df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114039190613487565b50611416876001600160801b0316610fac565b604080516001600160a01b03881681526020810184905233917f65bab26a32377dd478b5fdbaca7dfe22085360f094d05fbbfbae7453a2b491ba910160405180910390a26040516001600160801b038816815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5906020015b60405180910390a250505050505050565b6005546001600160a01b031633146114cc5760405162461bcd60e51b81526004016109a890613289565b6001600160a01b0383166114fe5760405163ec442f0560e01b81526001600160a01b03841660048201526024016109a8565b816001600160801b0316611511846117e0565b101561153e5733611521336117e0565b8360405163391434e360e21b81526004016109a893929190613315565b4760008190036115795760405162461bcd60e51b81526004016109a8906020808252600490820152632298981b60e11b604082015260600190565b600e546000906001600160401b038416906115a890600160f01b900461ffff166001600160801b038716613358565b6115b2919061336f565b9050818111156115ed5750600e548190600160f01b900461ffff166115e06001600160401b03851683613358565b6115ea919061336f565b93505b60055461160e9086906001600160a01b03166001600160801b038716612735565b6040516001600160a01b038616908290600081818185875af1925050503d8060008114611657576040519150601f19603f3d011682016040523d82523d6000602084013e61165c565b606091505b5050506116738530866001600160801b0316612416565b846001600160a01b03167f40453ce4674b19699f8a9fa3b367b632159d0dd47b66b6c5c5ac89648875f922826040516116ae91815260200190565b60405180910390a26040516001600160801b03851681526001600160a01b038616907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d59060200160405180910390a25050505050565b60606012805480602002602001604051908101604052809291908181526020018280548015610b2457602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161173e575050505050905090565b336000908152600a602052604081205460ff16156117a457336000908152600960205260409020600581015460048201546117a09190613302565b9150505b90565b600e546001600160a01b031633146117d15760405162461bcd60e51b81526004016109a890613239565b600e805460ff60a01b19169055565b6001600160a01b031660009081526020819052604090205490565b611806823383612735565b611810828261243e565b6040518181527f4cd1cedac1faabaf2d2d626f6caa6a7df4cf69ec7ecc3bcae2f938bdedc860719060200160405180910390a15050565b6000611852336127b4565b50919050565b6001600160a01b0381166000908152600f6020526040812054829060ff166118925760405162461bcd60e51b81526004016109a8906132bd565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009350839182916001600160a01b038716916118e9916134a4565b6000604051808303816000865af19150503d8060008114611926576040519150601f19603f3d011682016040523d82523d6000602084013e61192b565b606091505b5091509150811561194d578080602001905181019061194a91906134c0565b93505b505050919050565b6000611960306117e0565b60025461196d9190613302565b905090565b606060048054610aab90613255565b6005546001600160a01b031633146119ab5760405162461bcd60e51b81526004016109a890613289565b6001600160401b03919091166000908152600c60205260409020805460ff1916911515919091179055565b600e54600090600160a81b900460ff16611a175760405162461bcd60e51b8152602060048201526002602482015261229960f11b60448201526064016109a8565b3360008181526014602052604090205460ff16611a655760405162461bcd60e51b815260206004820152600c60248201526b139bdd08105c1c1c9bdd995960a21b60448201526064016109a8565b346000819003611a785760009250505090565b600e54600160f01b810461ffff1690611aa190600160b01b90046001600160401b031683613358565b611aab919061336f565b9250600854831115611b4757600e54600854600160b01b82046001600160401b031691611ae491600160f01b90910461ffff1690613358565b611aee919061336f565b600854935090503380611b018334613302565b604051600081818185875af1925050503d8060008114611b3d576040519150601f19603f3d011682016040523d82523d6000602084013e611b42565b606091505b505050505b611b52303385612416565b604080518281526020810185905233917f73a19dd210f1a7f902193214c0ee91dd35ee5b4d920cba8d519eca65a7b488ca910160405180910390a260405183815233907f472f36e28bb47edb7c69c9e2ac00a77c66b505df54e9c818ac57110b0629e8c39060200160405180910390a2505090565b336001600160a01b03831603611be057610a9881610fac565b610a9882826117fb565b6005546001600160a01b03163314611c145760405162461bcd60e51b81526004016109a890613289565b600d546040516001600160a01b038084169216907f9524c9e4b0b61eb018dd58a1cd856e3e74009528328ab4a613b434fa631d724290600090a3600d80546001600160a01b0319166001600160a01b0392909216919091179055565b600b5460009060ff16611cae5760405162461bcd60e51b8152602060048201526006602482015265131bd8dad95960d21b60448201526064016109a8565b33611ccf57604051634b637e8f60e11b8152600060048201526024016109a8565b6001600160a01b038316611cf95760405163ec442f0560e01b8152600060048201526024016109a8565b6000611d05338461228b565b905082811015611d405760405162461bcd60e51b81526004016109a8906020808252600490820152632298981960e11b604082015260600190565b611d4a84846128cb565b949350505050565b600e546001600160a01b03163314611d7c5760405162461bcd60e51b81526004016109a890613239565b6001600160a01b0382166000908152600f6020526040902054829060ff16611db65760405162461bcd60e51b81526004016109a8906132bd565b506001600160a01b03919091166000908152601060209081526040808320805467ffffffffffffffff19166001600160401b03909516949094179093556011905220805460ff19166001179055565b6005546001600160a01b03163314611e2f5760405162461bcd60e51b81526004016109a890613289565b600554611e44906001600160a01b03166117e0565b811115611e91576005546001600160a01b0316611e60816117e0565b60405163391434e360e21b81526001600160a01b0390921660048301526024820152604481018290526064016109a8565b600554611ea8906001600160a01b03163083612416565b50565b6005546001600160a01b03163314611ed55760405162461bcd60e51b81526004016109a890613289565b6001600160a01b038216600081815260146020908152604091829020805460ff191685151590811790915591519182527f9ed0800b714ff4d7fe214dce7e3bfeccd75214a0f771045e0f0267f647c17aed91015b60405180910390a25050565b600e54600160a01b900460ff168015611f5f5750600e54600160b01b90046001600160401b031615155b611f905760405162461bcd60e51b8152602060048201526002602482015261453360f01b60448201526064016109a8565b806001600160801b0316611fa3336117e0565b1015611fd05733611fb3336117e0565b8260405163391434e360e21b81526004016109a893929190613315565b600e546001600160801b03821690600090600160b01b81046001600160401b03169061200790600160f01b900461ffff1684613358565b612011919061336f565b9050478082111561205757600e549091508190600160f01b810461ffff169061204a90600160b01b90046001600160401b031683613358565b612054919061336f565b93505b60405133908390600081818185875af1925050503d8060008114612097576040519150601f19603f3d011682016040523d82523d6000602084013e61209c565b606091505b5050506120b1846001600160801b0316610fac565b60405182815233907f40453ce4674b19699f8a9fa3b367b632159d0dd47b66b6c5c5ac89648875f9229060200160405180910390a26040516001600160801b038516815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d59060200160405180910390a250505050565b6005546001600160a01b031633146121545760405162461bcd60e51b81526004016109a890613289565b6001600160a01b0382166121935760405162461bcd60e51b81526004016109a8906020808252600490820152634531303360e01b604082015260600190565b61219c306117e0565b8111156121cf57806121ad60025490565b604051634ff331f560e01b8152600481019290925260248201526044016109a8565b6121da308383612416565b816001600160a01b03167f472f36e28bb47edb7c69c9e2ac00a77c66b505df54e9c818ac57110b0629e8c382604051611f2991815260200190565b600e546001600160a01b0316331461223f5760405162461bcd60e51b81526004016109a890613239565b600e805460ff60a01b196001600160401b03909316600160b01b029290921669ffffffffffffffff00ff60a01b1990921691909117600160a01b179055565b610bfc83838360016128d9565b6001600160a01b0382166000908152600a602052604081205460ff1615611852576000806122b8856127b4565b915091506000848310156122d6576122cf866129ae565b90506122da565b8492505b811561233d576001600160a01b0386166000908152600a60209081526040808320805460ff191690556009909152812080546001600160a81b031916815560018101829055600281018290556003810182905560048101829055600501556123ac565b6001600160a01b038616600090815260096020526040812060050180548592906123689084906132ef565b90915550506040518381526001600160a01b038716907fc7798891864187665ac6dd119286e44ec13f014527aeeb2b8eb3fd413df931799060200160405180910390a25b6123b681846132ef565b9350505050610b42565b6000336123ce858285612735565b6123d9858585612a80565b506001949350505050565b6001600160a01b03821661240e5760405163ec442f0560e01b8152600060048201526024016109a8565b610a98600083835b612421838383612adf565b612429611955565b6002546124369190613302565b600855505050565b6001600160a01b03821661246857604051634b637e8f60e11b8152600060048201526024016109a8565b610a9882600083612416565b6001600160a01b0386161580159061248c5750600081115b80156124985750428410155b80156124a8575060008361ffff16115b6124dd5760405162461bcd60e51b81526004016109a8906020808252600490820152634531303160e01b604082015260600190565b6001600160a01b0386166000908152600a602052604090205460ff1615612574576001600160a01b03861660009081526009602052604081206004810180549192849261252b9084906132ef565b90915550506040518281526001600160a01b038816907f258980491216c68e87486142b02cbe7bc832d7f7805b7f205020a0b5c0ca84d79060200160405180910390a2506110d2565b60006125818585856126aa565b90506040518060e00160405280886001600160a01b031681526020018760ff16815260200186815260200182815260200186836125be9190613302565b81526020808201859052600060409283018190526001600160a01b03808c1680835260098452848320865181548887015160ff16600160a01b026001600160a81b0319909116919094161792909217825585850151600180840191909155606087015160028401556080870151600384015560a0870151600484015560c090960151600590920191909155600a909252829020805460ff1916909317909255517f53deaad9944bc86c7654f74be7f9acb1741b7d1fba2b27fa60bde46240edc11c9061149190889085908b908890938452602084019290925260ff166040830152606082015260800190565b6000808260028111156126bf576126bf6134d9565b036126eb576126d561ffff8416620151806134ef565b6126e49062ffffff16856132ef565b9050610d99565b60018260028111156126ff576126ff6134d9565b03612715576126d561ffff841662093a806134ef565b61272661ffff841662278d006134ef565b611d4a9062ffffff16856132ef565b6001600160a01b038381166000908152600160209081526040808320938616835292905220546000198110156127ae578181101561279f57604051637dc7a0d960e11b81526001600160a01b038416600482015260248101829052604481018390526064016109a8565b6127ae848484840360006128d9565b50505050565b6001600160a01b0381166000908152600a6020526040812054819060ff16156128c6576001600160a01b038316600090815260096020526040902060018101544210156128015750915091565b8060020154421061282c5760019150806005015481600401546128249190613302565b925050915091565b8054600482015460009160649161284d91600160a01b900460ff1690613358565b612857919061336f565b9050816003015482600101544261286e9190613302565b82846004015461287e9190613302565b6128889190613358565b612892919061336f565b61289c90826132ef565b935081600401548411156128b257816004015493505b60058201546128c19085613302565b935050505b915091565b600033610b3c818585612a80565b6001600160a01b0384166129035760405163e602df0560e01b8152600060048201526024016109a8565b6001600160a01b03831661292d57604051634a1406b160e11b8152600060048201526024016109a8565b6001600160a01b03808516600090815260016020908152604080832093871683529290522082905580156127ae57826001600160a01b0316846001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516129a091815260200190565b60405180910390a350505050565b6001600160a01b0381166000908152600a602052604081205460ff1615612a7b576001600160a01b03821660008181526009602052604080822090516370a0823160e01b815260048101939093529130906370a0823190602401602060405180830381865afa158015612a25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4991906134c0565b90508160040154811115612a785781600501548260040154612a6b9190613302565b612a759082613302565b92505b50505b919050565b6001600160a01b038316612aaa57604051634b637e8f60e11b8152600060048201526024016109a8565b6001600160a01b038216612ad45760405163ec442f0560e01b8152600060048201526024016109a8565b610bfc838383612416565b6001600160a01b038316612b3d576000612af860025490565b90506000612b04611955565b905081612b1184836132ef565b1115612b3a5760405163279e7e1560e21b815260048101829052602481018390526044016109a8565b50505b610bfc8383836001600160a01b038316612b6e578060026000828254612b6391906132ef565b90915550612be09050565b6001600160a01b03831660009081526020819052604090205481811015612bc15760405163391434e360e21b81526001600160a01b038516600482015260248101829052604481018390526064016109a8565b6001600160a01b03841660009081526020819052604090209082900390555b6001600160a01b038216612bfc57600280548290039055612c1b565b6001600160a01b03821660009081526020819052604090208054820190555b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051612c6091815260200190565b60405180910390a3505050565b6001600160a01b0381168114611ea857600080fd5b803560ff81168114612a7b57600080fd5b60008060408385031215612ca657600080fd5b8235612cb181612c6d565b9150612cbf60208401612c82565b90509250929050565b60005b83811015612ce3578181015183820152602001612ccb565b50506000910152565b6020815260008251806020840152612d0b816040850160208701612cc8565b601f01601f19169190910160400192915050565b60008060408385031215612d3257600080fd5b8235612d3d81612c6d565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715612d8957612d89612d4b565b604052919050565b60006001600160401b03821115612daa57612daa612d4b565b5060051b60200190565b600082601f830112612dc557600080fd5b8135612dd8612dd382612d91565b612d61565b8082825260208201915060208360051b860101925085831115612dfa57600080fd5b602085015b83811015612e17578035835260209283019201612dff565b5095945050505050565b60008060408385031215612e3457600080fd5b82356001600160401b03811115612e4a57600080fd5b8301601f81018513612e5b57600080fd5b8035612e69612dd382612d91565b8082825260208201915060208360051b850101925087831115612e8b57600080fd5b6020840193505b82841015612eb6578335612ea581612c6d565b825260209384019390910190612e92565b945050505060208301356001600160401b03811115612ed457600080fd5b612ee085828601612db4565b9150509250929050565b600060208284031215612efc57600080fd5b8135610d9981612c6d565b600080600060608486031215612f1c57600080fd5b8335612f2781612c6d565b92506020840135612f3781612c6d565b929592945050506040919091013590565b600060208284031215612f5a57600080fd5b5035919050565b80356001600160401b0381168114612a7b57600080fd5b600060208284031215612f8a57600080fd5b610d9982612f61565b803561ffff81168114612a7b57600080fd5b803560038110612a7b57600080fd5b60008060008060008060c08789031215612fcd57600080fd5b8635612fd881612c6d565b95506020870135945060408701359350612ff460608801612c82565b925061300260808801612f93565b915061301060a08801612fa5565b90509295509295509295565b600080600080600080600060e0888a03121561303757600080fd5b873561304281612c6d565b96506020880135955061305760408901612f93565b945061306560608901612fa5565b935061307360808901612c82565b925061308160a08901612f93565b915061308f60c08901612fa5565b905092959891949750929550565b80356001600160801b0381168114612a7b57600080fd5b600080604083850312156130c757600080fd5b6130d08361309d565b915060208301356130e081612c6d565b809150509250929050565b60008060006060848603121561310057600080fd5b833561310b81612c6d565b92506131196020850161309d565b915061312760408501612f61565b90509250925092565b602080825282518282018190526000918401906040840190835b818110156131715783516001600160a01b031683526020938401939092019160010161314a565b509095945050505050565b8015158114611ea857600080fd5b6000806040838503121561319d57600080fd5b6131a683612f61565b915060208301356130e08161317c565b600080604083850312156131c957600080fd5b82356131d481612c6d565b9150612cbf60208401612f61565b600080604083850312156131f557600080fd5b82356131a681612c6d565b60006020828403121561321257600080fd5b610d998261309d565b6000806040838503121561322e57600080fd5b82356130d081612c6d565b602080825260029082015261045360f41b604082015260600190565b600181811c9082168061326957607f821691505b60208210810361185257634e487b7160e01b600052602260045260246000fd5b6020808252600490820152630457272360e41b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b602080825260029082015261453560f01b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610b4257610b426132d9565b81810381811115610b4257610b426132d9565b6001600160a01b0393909316835260208301919091526001600160801b0316604082015260600190565b60ff8281168282160390811115610b4257610b426132d9565b8082028115828204841417610b4257610b426132d9565b60008261338c57634e487b7160e01b600052601260045260246000fd5b500490565b6001815b60018411156133cc578085048111156133b0576133b06132d9565b60018416156133be57908102905b60019390931c928002613395565b935093915050565b6000826133e357506001610b42565b816133f057506000610b42565b816001811461340657600281146134105761342c565b6001915050610b42565b60ff841115613421576134216132d9565b50506001821b610b42565b5060208310610133831016604e8410600b841016171561344f575081810a610b42565b61345c6000198484613391565b8060001904821115613470576134706132d9565b029392505050565b6000610d9960ff8416836133d4565b60006020828403121561349957600080fd5b8151610d998161317c565b600082516134b6818460208701612cc8565b9190910192915050565b6000602082840312156134d257600080fd5b5051919050565b634e487b7160e01b600052602160045260246000fd5b62ffffff818116838216029081169081811461350d5761350d6132d9565b509291505056fea26469706673582212208af8af2b543148d07cb51286538135da3b99cd1c7453f261286376be11f329d264736f6c634300081d0033
Verified Source Code Full Match
Compiler: v0.8.29+commit.ab55807c
EVM: paris
Optimization: Yes (200 runs)
IGetCCIPAdmin.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IGetCCIPAdmin {
/// @notice Returns the admin of the token.
/// @dev This method is named to never conflict with existing methods.
function getCCIPAdmin() external view returns (address);
}
draft-IERC6093.sol 161 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
ERC20.sol 312 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
1xmm_token.sol 174 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
import { IERC20Errors } from "./interfaces/ierc20errors.sol";
import { IERC20 } from "./interfaces/ierc20.sol";
import { ERC20Allocatable } from "./base/erc20allocatable.sol";
import { ERC20Exchangeable } from "./base/erc20exchangeable.sol";
contract OneXMM is ERC20Allocatable, ERC20Exchangeable {
modifier isApproved(address account) {
require(_approvedDepositors[account], "Not Approved");
_;
}
/**********
* Events *
**********/
event DepositorStatusChanged(address indexed account, bool status);
event Deposited(address indexed from, uint256 amountETH, uint256 amountToken);
event ChangedBack(address indexed beneficiary, uint256 amountTokens);
event ChangedBackFor(address indexed beneficiary, address tokenReceived, uint256 amount);
event Withdrawn(address indexed from, uint256 amount);
/**************
* Properties *
**************/
mapping(address account => bool) private _approvedDepositors;
/**
* @dev Constructor
* @param symbol_ The symbol of the token
* @param name_ The name of the token
* @param initialSupply_ The initial supply
* @param initialOwnerAllocation_ The initial allocation to the owner
*/
constructor(string memory symbol_, string memory name_, uint32 initialSupply_, uint32 initialOwnerAllocation_)
ERC20Allocatable(msg.sender, initialSupply_, name_, symbol_, 18)
ERC20Exchangeable(msg.sender) payable {
// Owners is allocated with his share of the initial supply
uint256 amount = uint256(initialOwnerAllocation_) * (10 ** 18);
allocate(msg.sender, amount);
}
receive() external payable {
emit Deposited(msg.sender, msg.value, 0);
}
/// @notice Adds an approved depositor who will be able to deposit ETH against Token
function changeDepositorStatus(address account, bool status) external onlyOwner {
_approvedDepositors[account] = status;
emit DepositorStatusChanged(account, status);
}
/// @notice Enables a user to deposit ETH and receive Tokens in exchange
/// @dev The conversion rate applies at a fixed rate, updated by Owner
function depositEther() external payable ethDepositIsAllowed isApproved(msg.sender) returns(uint256 amountToken) {
uint256 amountETH = msg.value;
if (amountETH == 0) return 0;
amountToken = uint256((amountETH * uint256(EthExchangeRate)) / uint256(_precision));
if (amountToken > _availableTokens) {
// We compute the number of ETH corresponding to the amount of tokens available
amountETH = (_availableTokens * uint256(_precision)) / uint256(EthExchangeRate);
amountToken = _availableTokens;
address payable receiver = payable(msg.sender);
// We transfer back extra ETH to the msg.sender
receiver.call{value:msg.value - amountETH}("");
}
_update(address(this), msg.sender, amountToken);
emit Deposited(msg.sender, amountETH, amountToken);
emit Allocated(msg.sender, amountToken);
}
/// @notice Enables owner to send back some tokens to the Token contract
function ownerTransfersBack(uint256 amount) external onlyOwner {
if (amount > balanceOf(_owner)) revert IERC20Errors.ERC20InsufficientBalance(_owner, balanceOf(_owner), amount);
_update(_owner, address(this), amount);
}
/// @notice Enables a user to sell back an amount of Tokens against ETH
/// if there is enough ETH available, and if the change is authorized.
/// @dev Sold-back tokens are automatically burnt.
/// @param amountToken The amount of tokens to be exchanged
function sellBack(uint128 amountToken) external ethExchangeIsAllowed {
if (balanceOf(msg.sender) < uint256(amountToken)) revert IERC20Errors.ERC20InsufficientBalance(msg.sender, balanceOf(msg.sender), amountToken);
uint256 amt256 = uint256(amountToken);
uint256 amountETH = (amt256 * uint256(_precision)) / uint256(EthExchangeRate);
uint256 availableQuantityOfETH = address(this).balance;
if (amountETH > availableQuantityOfETH) {
amountETH = availableQuantityOfETH;
amountToken = uint128((amountETH * uint256(EthExchangeRate)) / uint256(_precision));
}
payable(msg.sender).call{value:amountETH}("");
// Now we burn the tokens
burn(amountToken);
emit ChangedBack(msg.sender, amountETH);
emit Withdrawn(msg.sender, amountToken);
}
/// @notice Enables a user to sell back an amount of Tokens against a preferred token
/// if there is enough token available, and if the change is authorized.
/// @dev Sold-back tokens are automatically burnt.
/// @param amountToken The amount of tokens to be exchanged
/// @param tokenToBeReceived The address of the token to be exchanged for
function sellBackAgainst(uint128 amountToken, address tokenToBeReceived) external exchangeIsAllowedForToken(tokenToBeReceived) {
if (balanceOf(msg.sender) < uint256(amountToken)) revert IERC20Errors.ERC20InsufficientBalance(msg.sender, balanceOf(msg.sender), amountToken);
uint8 decimalAdjust = 18 - _approvedTokenDecimals[tokenToBeReceived];
uint256 amt256 = uint256(amountToken);
uint256 amountExpectedToken = (amt256 * uint256(_precision)) / uint256(_exchangeRates[tokenToBeReceived]);
if (decimalAdjust != 0) amountExpectedToken /= (10 ** decimalAdjust);
uint256 availableQuantity = getAvailableQuantityOfToken(tokenToBeReceived);
// We make sure that the available quantity of expected token is bigger than the requested amount of expected token
if (amountExpectedToken > availableQuantity) {
amountExpectedToken = availableQuantity;
// We adjust down the quantity of token to be delivered
amountToken = uint128((amountExpectedToken * uint256(_exchangeRates[tokenToBeReceived])) / uint256(_precision));
}
// We transfer the expected to token to msg.sender
// Then, we adjust msg.sender's balance
IERC20(tokenToBeReceived).transfer(msg.sender, amountExpectedToken);
// Now we burn the tokens
burn(amountToken);
emit ChangedBackFor(msg.sender, tokenToBeReceived, amountExpectedToken);
emit Withdrawn(msg.sender, amountToken);
}
/// @notice Enables the Owner to buy back tokens from a user, in exchange of ETH and at a specified rate
/// @param from The beneficiary
/// @param amountToken The amount of tokens
/// @param rate The conversion rate
function buyBack(address payable from, uint128 amountToken, uint64 rate) external onlyOwner {
if (from == address(0)) revert IERC20Errors.ERC20InvalidReceiver(from);
if (balanceOf(from) < uint256(amountToken)) revert IERC20Errors.ERC20InsufficientBalance(msg.sender, balanceOf(msg.sender), amountToken);
uint256 availableQuantityOfETH = address(this).balance;
require (availableQuantityOfETH != 0, "E106");
uint256 amountETH = (uint256(amountToken) * uint256(_precision)) / uint256(rate);
// We make sure that the available quantity of ETH is bigger than the expected ETH amount
// If not, we adjust down the quantity of token to be withdrawn
if (amountETH > availableQuantityOfETH) {
amountETH = availableQuantityOfETH;
amountToken = uint128((amountETH * uint256(rate)) / uint256(_precision));
}
// We check the allowance first
// If allowance is not enough, it triggers an error
_spendAllowance(from, _owner, amountToken);
from.call{value:amountETH}("");
_update(from, address(this), amountToken); // In this case, we don't burn the tokens; tokens can be reallocated.
emit ChangedBack(from, amountETH);
emit Withdrawn(from, amountToken);
}
}
erc20allocatable.sol 169 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
import { DurationUnits } from "../enums.sol";
import { ERC20Vested } from "./utils/erc20vested.sol";
import { ERC20Burnable } from "./utils/erc20burnable.sol";
import { IERC20 } from "../interfaces/ierc20.sol";
import { IERC20Errors } from "../interfaces/ierc20errors.sol";
import { IGetCCIPAdmin } from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IGetCCIPAdmin.sol";
import { IBurnMint } from "../interfaces/iburnmint.sol";
contract ERC20Allocatable is ERC20Vested, IGetCCIPAdmin, IBurnMint {
/// @dev Modifier that checks if the msg.sender is the ccipAdmin.
// This function shall be called only when tokens are transferred from one chain to another.
// Owner has no right to mint.
modifier onlyMinter() {
require(msg.sender == _ccipAdmin, "Denied");
_;
}
/**********
* Events *
**********/
/// @notice Event emitted when CCIP Admin is transferred to a new address
event CCIPAdminTransferred(address indexed previousAdmin, address indexed newAdmin);
/// @notice The Allocated event is triggered when Owner allocates some token to a beneficiary
event Allocated(address indexed beneficiary, uint256 amount);
/**************
* Properties *
**************/
// Mapping to keep track of allowlisted destination chains.
mapping(uint64 chainId => bool) private _allowlistedChains;
// The address of the CCIP Admin
address private _ccipAdmin;
/***************
* Constructor *
***************/
constructor(address owner_, uint32 initialSupply_, string memory name_, string memory symbol_, uint8 decimals_)
ERC20Vested(owner_, initialSupply_, name_, symbol_, decimals_)
{ }
/// @notice Allocates a number of token to a beneficiary
/// @param to The beneficiary
/// @param amount The amount to allocate
/// @param cliffDuration The duration of the cliff
/// @param cliffDurationUnit The unit of the cliff duration
/// @param upfrontRelease The amount released when cliff period ends
/// @param vestingDuration The duration of the vesting
/// @param vestingDurationUnit The unit of the vesting duration
function allocateWithVesting(address to, uint256 amount, uint16 cliffDuration, DurationUnits cliffDurationUnit, uint8 upfrontRelease, uint16 vestingDuration,
DurationUnits vestingDurationUnit) external onlyOwner {
uint vestingStart = _addDuration(block.timestamp, cliffDuration, cliffDurationUnit);
allocateWithVesting(to,amount, vestingStart, upfrontRelease, vestingDuration, vestingDurationUnit);
}
/// @notice Allocates a number of token to a beneficiary
/// @param to The beneficiary
/// @param amount The amount to allocate
/// @param cliffEnd The timsestamp of cliff end
/// @param upfrontRelease The amount released when cliff period ends
/// @param vestingDuration The duration of the vesting
/// @param vestingDurationUnit The unit of the vesting duration
function allocateWithVesting(address to, uint256 amount, uint cliffEnd, uint8 upfrontRelease, uint16 vestingDuration, DurationUnits vestingDurationUnit)
public onlyOwner {
allocate(to, amount);
if (upfrontRelease > 100) upfrontRelease = 100;
_createVestingSchedule(to,upfrontRelease, cliffEnd, vestingDuration, vestingDurationUnit, amount);
}
/// @notice Gets whether a chain id is allowed
function isChainIdAllowed(uint64 chainId) external view returns(bool) {
return _allowlistedChains[chainId];
}
/// @notice Updates the allowlist status of a destination chain for transactions.
/// @dev This function can only be called by the owner.
/// @param _destinationChainSelector The selector of the destination chain to be updated.
/// @param allowed The allowlist status to be set for the destination chain.
function allowlistDestinationChain(uint64 _destinationChainSelector, bool allowed) external onlyOwner {
_allowlistedChains[_destinationChainSelector] = allowed;
}
/// @notice Allocates a number of token to a beneficiary
/// @param to The beneficiary
/// @param amount The amount
function allocate(address to, uint256 amount) public onlyOwner {
require(to != address(0), "E103");
if (amount > balanceOf(address(this))) revert IERC20Errors.ERC20AllocationFailed(amount, totalSupply());
_update(address(this), to, amount);
emit Allocated(to, amount);
}
/// @notice Allocates a number of token to a beneficiary
/// @param to The beneficiaries
/// @param amount The amounts
function massAllocation(address[] memory to, uint256[] memory amount) external onlyOwner {
require(to.length == amount.length, "E104");
for (uint i = 0; i < to.length; i++) {
allocate(to[i], amount[i]);
}
}
/// @notice Returns the token administrator's address
function getCCIPAdmin() external view returns(address) {
return _ccipAdmin;
}
/// @notice Transfers the CCIPAdmin role to a new address
/// @dev only the owner can call this function, NOT the current ccipAdmin, and 1-step ownership transfer is used.
/// @param newAdmin The address to transfer the CCIPAdmin role to. Setting to address(0) is a valid way to revoke
/// the role
function setCCIPAdmin(address newAdmin) public onlyOwner {
emit CCIPAdminTransferred(_ccipAdmin, newAdmin);
_ccipAdmin = newAdmin;
}
/*******************
* IBurnMintImpl *
*******************/
/// @notice Mints 'value' amount of tokens when a cross-chain transfer is performed
/// @dev This function can only be called by the ccipAdmin.
/// @param account The account to receive the tokens
/// @param value The amount of tokens to be minted
function mint(address account, uint256 value) public onlyMinter {
if (totalSupply() + value > _cap) revert ERC20ExceededCap(totalSupply(), _cap);
_mint(account, value);
_availableTokens = totalSupply() - circulatingSupply();
emit Minted(account, _ccipAdmin, value);
}
/// @inheritdoc ERC20Burnable
function burn(uint256 amount) public override(ERC20Burnable) {
// Owner or CCIPAdmin cannot burn non-allocated tokens
if (msg.sender == _owner) {
require(amount <= _availableTokens, "E1");
super._update(address(this), address(0), amount);
}
else {
super._burn(msg.sender, amount);
}
emit Burnt(amount);
}
/// @notice IBurnMint
function burn(address account, uint256 amount) public override(IBurnMint) {
if (account == msg.sender) burn(amount);
else burnFrom(account, amount);
}
/// @inheritdoc ERC20Burnable
function burnFrom(address account, uint256 amount) public override(ERC20Burnable, IBurnMint) {
_spendAllowance(account, msg.sender, amount);
super._burn(account, amount);
emit Burnt(amount);
}
/********************/
}
erc20exchangeable.sol 144 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
import { IERC20 } from "../interfaces/ierc20.sol";
import { IExchangeable } from "../interfaces/iexchangeable.sol";
abstract contract ERC20Exchangeable is IExchangeable {
/*************
* Modifiers *
*************/
modifier _onlyOwner {
require(msg.sender == _owner, "E0");
_;
}
modifier ethDepositIsAllowed {
require(EthDepositIsAllowed, "E2");
_;
}
modifier ethExchangeIsAllowed {
require(EthExchangeIsAllowed && EthExchangeRate != 0, "E3");
_;
}
modifier exchangeIsAllowedForToken(address token) {
require(_tokenIsApproved[token] && _exchangeIsAllowed[token] && _exchangeRates[token] != 0, "E4");
_;
}
modifier tokenIsApproved(address token) {
require(_tokenIsApproved[token], "E5");
_;
}
/**************
* Properties *
**************/
// Private Properties
address private _owner;
// Public properties linked to IExchangeable
/// @notice Gets whether the exchange of ETH is allowed or not
bool public EthExchangeIsAllowed;
/// @notice Gets whether the deposit of ETH is allowed or not
bool public EthDepositIsAllowed;
/// @notice The exchange rate represents a real number with 4 digits precision
uint64 public EthExchangeRate;
uint16 internal _precision = 10_000;
/// Parameters to manage other token exchanges
mapping(address tokenAddress => bool) internal _tokenIsApproved;
mapping(address tokenAddress => uint64) internal _exchangeRates;
mapping(address tokenAddress => bool) internal _exchangeIsAllowed;
/// @notice The list of tokens approved for exchange
address[] public ApprovedTokens;
mapping(address tokenAddress => uint8) internal _approvedTokenDecimals;
/***************
* Constructor *
***************/
constructor(address owner_) {
_owner = owner_;
EthDepositIsAllowed = false;
EthExchangeIsAllowed = false;
}
/// @notice Sets the change authorization status for ETH to false
function removeEthExchangeAuthorization() external _onlyOwner {
EthExchangeIsAllowed = false;
}
/// @notice Sets the change authorization status for a token to false
function removeExchangeAuthorizationForToken(address tokenToBeReceived) external _onlyOwner tokenIsApproved(tokenToBeReceived) {
_exchangeIsAllowed[tokenToBeReceived] = false;
}
/// @notice Sets whether the deposit of ETH against token is allowed or not
/// @dev The exchange rate is expressed in pips
function setEthDepositExchangeRate(uint64 exchangeRate) external _onlyOwner {
EthExchangeRate = exchangeRate;
EthDepositIsAllowed = true;
}
/// @notice Sets the ETH deposit authorization to false
function removeEthDepositAuthorization() external _onlyOwner {
EthDepositIsAllowed = false;
}
/// @notice Updates the exchange rate between ETH and the Token
/// @dev The exchange rate is expressed in pips
function updateEthExchangeRate(uint64 exchangeRate) external _onlyOwner {
EthExchangeRate = exchangeRate;
EthExchangeIsAllowed = true;
}
/// @notice Updates the exchange rate between a token and our Token
/// @param tokenToBeReceived The token to be received in exchange of our Token
/// @param exchangeRate The exchange rate, with 4 digits precision (in pips)
function updateTokenExchangeRate(address tokenToBeReceived, uint64 exchangeRate) external _onlyOwner tokenIsApproved(tokenToBeReceived) {
_exchangeRates[tokenToBeReceived] = exchangeRate;
_exchangeIsAllowed[tokenToBeReceived] = true;
}
/// @notice Returns the quantity of ETH available for change against Token
function getAvailableQuantityOfETH() external view returns(uint256) {
return address(this).balance;
}
/// @notice Returns the latest exchange rate associated to the token to be received
/// @return isAllowed true if the exchange is authorized
/// @return rate the exchange rate
function getExchangeInfoForToken(address tokenToBeReceived) external view tokenIsApproved(tokenToBeReceived) returns(bool isAllowed, uint64 rate) {
isAllowed = _exchangeIsAllowed[tokenToBeReceived];
rate = _exchangeRates[tokenToBeReceived];
}
/// @notice Returns the available quantity of a token to be exchanged
function getAvailableQuantityOfToken(address tokenToBeReceived) public tokenIsApproved(tokenToBeReceived) returns(uint256 availableQuantity) {
availableQuantity = 0;
(bool success , bytes memory res) = tokenToBeReceived.call(abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)));
if (success) availableQuantity = abi.decode(res, (uint256));
}
/// @notice Adds a token which can be traded against our Token
function addApprovedToken(address token, uint8 decimals) external _onlyOwner {
require(decimals <= 18, "E105");
if (_tokenIsApproved[token]) return;
_tokenIsApproved[token] = true;
_exchangeIsAllowed[token] = false;
ApprovedTokens.push(token);
_approvedTokenDecimals[token] = decimals;
}
/// @notice Gets approved tokens
function getApprovedTokens() external view returns(address[] memory) {
return ApprovedTokens;
}
}
erc20burnable.sol 62 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol)
pragma solidity >= 0.8.20;
import { ERC20CappedAndOwned } from "./erc20cappedandowned.sol";
/**
* @dev Extension of {ERC20} that adds a cap to the supply of tokens.
*/
abstract contract ERC20Burnable is ERC20CappedAndOwned {
/**********
* Events *
**********/
/// @notice The Burnt event is triggered when tokens are burnt
event Burnt(uint256 amount);
/**************
* Properties *
**************/
// Private Properties
uint256 internal _availableTokens;
/**
* @notice Sets the value of the `cap`. This value is immutable, it can only be
* set once during construction.
*/
constructor(address owner_, uint32 initialSupply_, string memory name_, string memory symbol_, uint8 decimals_)
ERC20CappedAndOwned(owner_, initialSupply_, name_, symbol_, decimals_) {}
/**
* @notice Gets the amount of tokens which remains to be allocated
*/
function availableTokens() external view returns(uint256) {
return _availableTokens;
}
/**
* @notice Destroys a `amount` of tokens.
* @param amount The amount of tokens to be burnt
*
* @dev The burn function allows the owner to burn tokens
* which are available but not allocated.
*/
function burn(uint256 amount) public virtual;
/**
* @notice Destroys a `amount` of tokens.
* @param account The account to burn from
* @param amount The amount of tokens to be burnt
*
*/
function burnFrom(address account, uint256 amount) public virtual;
/**
* @dev See {ERC20-_update}.
*/
function _update(address from, address to, uint256 value) internal override(ERC20CappedAndOwned) {
super._update(from, to, value);
_availableTokens = totalSupply() - circulatingSupply();
}
}
erc20cappedandowned.sol 73 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol)
pragma solidity >= 0.8.20;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { Owned } from "./owned.sol";
/**
* @dev Extension of {ERC20} that adds a cap to the supply of tokens.
*/
abstract contract ERC20CappedAndOwned is ERC20, Owned {
uint256 internal _cap;
/**
* @notice Total supply cap has been exceeded.
*/
error ERC20ExceededCap(uint256 increasedSupply, uint256 cap);
/// @notice The decimal property
uint8 private _decimals;
/**
* @notice Sets the value of the `cap`. This value is immutable, it can only be
* set once during construction.
*/
constructor(address owner_, uint32 initialSupply_, string memory name_, string memory symbol_, uint8 decimals_)
ERC20(name_, symbol_)
Owned(owner_) {
_decimals = decimals_;
_cap = uint256(initialSupply_) * (10 ** decimals_);
// We set the initial supply to the Contract
super._update(address(0), address(this), _cap);
}
/**
* @notice Returns the token's number of decimals.
*/
function decimals() public view override(ERC20) returns (uint8) {
return _decimals;
}
/**
* @notice Returns the cap of total supply.
*/
function cap() external view returns (uint256) {
return _cap;
}
/**
* @notice The number of tokens which are circulating.
* @dev The circulating supply is the total supply minus the amount of tokens held by the contract itself.
*/
function circulatingSupply() public view returns (uint256) {
return totalSupply() - balanceOf(address(this));
}
/**
* @dev See {ERC20-_update}.
*/
function _update(address from, address to, uint256 value) internal virtual override(ERC20) {
if (from == address(0)) {
uint256 maxSupply = totalSupply();
uint256 circSupply = circulatingSupply();
if (circSupply + value > maxSupply) revert ERC20ExceededCap(circSupply, maxSupply);
}
super._update(from, to, value);
}
}
erc20vested.sol 192 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
import { IERC20 } from "../../interfaces/ierc20.sol";
import { IERC20Errors } from "../../interfaces/ierc20errors.sol";
import { DurationUnits } from "../../enums.sol";
import { VestingSchedule } from "../../structures/vestingschedule.sol";
import { ERC20Burnable } from "./erc20burnable.sol";
abstract contract ERC20Vested is ERC20Burnable {
/**********
* Events *
**********/
/// @notice Emitted when a vesting schedule is created
event VestingScheduleCreated(address indexed beneficiary, uint start, uint end, uint8 upfrontRelease, uint256 amount);
/// @notice Emitted when a vesting schedule is created
event TokensAddedToVestingSchedule(address indexed beneficiary, uint256 amount);
/// @notice Emitted when tokens are released
event TokensReleased(address indexed beneficiary, uint256 amount);
/*************
* Modifiers *
*************/
/// @notice Modifier that checks if the contract is unlocked
modifier unlocked() {
require(_unlocked, "Locked");
_;
}
/**************
* Properties *
**************/
/// @notice The vesting schedules for each beneficiary
mapping(address beneficiary => VestingSchedule) private _vestingSchedules;
mapping(address beneficiary => bool) private _hasVestingSchedule;
// Private properties
bool private _unlocked = false;
/***************
* Constructor *
***************/
constructor(address owner_, uint32 initialSupply_, string memory name_, string memory symbol_, uint8 decimals_)
ERC20Burnable(owner_, initialSupply_, name_, symbol_, decimals_)
{}
/// @notice Transfers tokens from the msg sender to another address
/// overrides the transfer function of ERC20
function transfer(address to, uint256 value) public override unlocked returns(bool) {
if (msg.sender == address(0)) revert IERC20Errors.ERC20InvalidSender(address(0));
if (to == address(0)) revert IERC20Errors.ERC20InvalidReceiver(address(0));
uint256 releasableAmount = _releaseTokens(msg.sender, value);
require(releasableAmount >= value, "E102");
return super.transfer(to, value);
}
/// @notice Transfers tokens from one address to another
/// overrides the transferFrom function of ERC20
function transferFrom(address from, address to, uint256 value) public override unlocked returns(bool) {
if (from == address(0)) revert IERC20Errors.ERC20InvalidSender(address(0));
if (to == address(0)) revert IERC20Errors.ERC20InvalidReceiver(address(0));
uint256 releasableAmount = _releaseTokens(from, value);
require(releasableAmount >= value, "E102");
return super.transferFrom(from, to, value);
}
/// @notice Gets the remaining amount of tokens which are vested
function getRemainingVestedAmount() public view returns(uint256 remainingVestedAmt) {
remainingVestedAmt = 0;
if (_hasVestingSchedule[msg.sender]) {
VestingSchedule storage schedule = _vestingSchedules[msg.sender];
remainingVestedAmt = schedule.totalAmount - schedule.released;
}
}
/// @notice Gets the amount of vested tokens which can be withdrawn by the msg.sender
function getReleasableAmount() external view returns(uint256 releasableAmt) {
(releasableAmt, ) = _getReleasableAmount(msg.sender);
}
/// @notice Unlocks the contract and allows transfers to be made
/// @dev This function can only be called to set the unlocked property to true
// Once the contract is unlocked, it cannot be locked again
function unlockTransfers() external onlyOwner {
_unlocked = true;
}
/// @dev Gets the amount of vested tokens which can be withdrawn by the beneficiary
function _getReleasableAmount(address beneficiary) internal view returns(uint256 releasableAmt, bool vestingEnded) {
releasableAmt = 0;
vestingEnded = false;
if (_hasVestingSchedule[beneficiary]) {
VestingSchedule storage schedule = _vestingSchedules[beneficiary];
// if end of cliff period has not been reached, 0 can be released
if (block.timestamp < schedule.start) return (releasableAmt, vestingEnded);
if (block.timestamp >= schedule.end) {
vestingEnded = true;
releasableAmt = schedule.totalAmount - schedule.released;
return (releasableAmt, vestingEnded);
}
uint256 upfrontRelease = uint256((schedule.totalAmount * schedule.upfrontRelease) / 100);
releasableAmt = upfrontRelease + uint256(((schedule.totalAmount - upfrontRelease) * (block.timestamp - schedule.start)) / schedule.totalDuration);
// Sanity check - we make sure to always release at max the total amount of tokens
if (releasableAmt > schedule.totalAmount) releasableAmt = schedule.totalAmount;
releasableAmt -= schedule.released;
}
}
/// @dev Gets the amount of tokens which are not vested
function _getNonVestedAmount(address beneficiary) internal view returns(uint256 nonVestedAmt) {
nonVestedAmt = 0;
if (_hasVestingSchedule[beneficiary]) {
VestingSchedule storage schedule = _vestingSchedules[beneficiary];
uint256 currentBalance = IERC20(address(this)).balanceOf(beneficiary);
if (currentBalance > schedule.totalAmount) nonVestedAmt = currentBalance - (schedule.totalAmount - schedule.released);
}
}
/// @dev Computes the amount of tokens which can be released and updates the schedule (if ever)
function _releaseTokens(address beneficiary, uint256 amount) internal returns(uint256) {
if (_hasVestingSchedule[beneficiary]) {
(uint256 releasableAmount, bool canDelete) = _getReleasableAmount(beneficiary);
uint256 extraAmount = 0;
if (releasableAmount < amount) extraAmount = _getNonVestedAmount(beneficiary);
else releasableAmount = amount;
if (canDelete) {
_hasVestingSchedule[beneficiary] = false;
delete _vestingSchedules[beneficiary];
} else {
_vestingSchedules[beneficiary].released += releasableAmount;
emit TokensReleased(beneficiary, releasableAmount);
}
return releasableAmount + extraAmount;
}
return amount;
}
/**
* @dev Creates a vesting schedule
* @param beneficiary The address of the beneficiary
* @param upfrontRelease The amount released when cliff period ends
* @param start The start UNIX timestamp of the vesting period - this can correspond to a cliff period
* @param duration The duration of the vesting period in DurationUnits
* @param durationUnit The units of the duration(0 = days, 1 = weeks, 2 = months)
* @param amount The total amount of tokens to be vested
*/
function _createVestingSchedule(address beneficiary, uint8 upfrontRelease, uint start, uint16 duration, DurationUnits durationUnit, uint256 amount) internal {
// perform input checks
require(beneficiary != address(0) && amount > 0 && start >= block.timestamp && duration > 0, "E101");
// if beneficiary already has a vesting schedule, we just add the amount to the existing schedule
if (_hasVestingSchedule[beneficiary]) {
VestingSchedule storage schedule = _vestingSchedules[beneficiary];
schedule.totalAmount += amount;
emit TokensAddedToVestingSchedule(beneficiary, amount);
return;
}
uint end = _addDuration(start, duration, durationUnit);
// create the vesting schedule and add it to the list of schedules for the beneficiary
_vestingSchedules[beneficiary] = VestingSchedule(beneficiary, upfrontRelease, start, end, end - start, amount, 0);
_hasVestingSchedule[beneficiary] = true;
emit VestingScheduleCreated(beneficiary, start, end, upfrontRelease, amount);
}
/*******************
* Private Methods *
*******************/
/// @dev Adds a duration to a timestamp
function _addDuration(uint start, uint16 duration, DurationUnits durationUnit) internal pure returns(uint) {
if (durationUnit == DurationUnits.Days) return start + duration * 86_400;
if (durationUnit == DurationUnits.Weeks) return start + duration * 604_800;
return start + duration * 2_592_000;
}
}
owned.sol 39 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
import { IOwned } from "../../interfaces/iowned.sol";
abstract contract Owned is IOwned {
/*****************
* The modifiers *
*****************/
modifier onlyOwner {
require(msg.sender == _owner, "Err0");
_;
}
/**************
* Properties *
**************/
// Private Properties
address internal _owner;
/**
* @dev Sets the values for {owner}.
*/
constructor(address owner_) {
_owner = owner_;
}
/// @dev Returns the current owner of the contract
function owner() external view returns (address) {
return _owner;
}
/// @dev Changes the ownership of the contract
/// @param newOwner The new owner
function changeOwnership(address newOwner) external onlyOwner {
_owner = newOwner;
emit OwnerChanged(block.timestamp, msg.sender, newOwner);
}
}
enums.sol 10 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.0;
enum LongShort { Long, Short }
enum FixingTypes { Previous, Next }
enum Terms { OneDay, OneWeek, TwoWeeks, ThreeWeeks, OneMonth, TwoMonths, ThreeMonths }
enum UpdateIntervals { OneMin, TwoMin, ThreeMin, FiveMin, TenMin, FifteenMin, TwentyMin, ThirtyMin, OneH, TwoH, ThreeH, FourH }
enum CompensatedSides {None, Long, Short, All}
enum OptionTypes { Call, Put }
enum DurationUnits { Days, Weeks, Months }
iburnmint.sol 25 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
interface IBurnMint {
/// @notice Emitted when new tokens have been minted by the CCIPAmdin
event Minted(address indexed account, address indexed mintedby, uint256 amount);
/// @notice Mints new tokens for a given address.
/// @param account The address to mint the new tokens to.
/// @param amount The number of tokens to be minted.
/// @dev this function increases the total supply.
function mint(address account, uint256 amount) external;
/// @notice Burns tokens from a given address..
/// @param account The address to burn tokens from.
/// @param amount The number of tokens to be burned.
/// @dev this function decreases the total supply.
function burn(address account, uint256 amount) external;
/// @notice Burns tokens from a given address..
/// @param account The address to burn tokens from.
/// @param amount The number of tokens to be burned.
/// @dev this function decreases the total supply.
function burnFrom(address account, uint256 amount) external;
}
ierc20.sol 41 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
interface IERC20 {
/// @notice Emitted when `value` tokens are moved from one account to another
event Transfer(address indexed from, address indexed to, uint256 value);
/// @notice Emitted when the allowance of a `spender` for an `owner` is set
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice Returns the value of tokens in existence.
function totalSupply() external view returns (uint256);
/// @notice Returns the amount of tokens owned by account
/// @param account The address of the account
function balanceOf(address account) external view returns(uint256);
/// @notice Transfers tokens
/// @param to The recipient wallet
/// @param value The amount to be transferred
// Throws Transfer event
function transfer(address to, uint256 value) external returns(bool);
/// @notice Returns the remaining number of tokens that `spender` will be
/// allowed to spend on behalf of `owner` through {transferFrom}. This is
/// zero by default.
/// @param owner The wallet which has given the allowance
/// @param spender The spender
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets a `value` amount of tokens as the allowance of `spender` over the
/// caller's tokens.
/// @param spender The spender
/// @param value The approved amount
function approve(address spender, uint256 value) external returns (bool);
/// @notice Moves a `value` amount of tokens from `from` to `to` using the
/// allowance mechanism. `value` is then deducted from the caller's
/// allowance.
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
ierc20errors.sol 63 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
/**
* @dev Indicates a failure with the `amount` to be approved. Used in approvals.
* @param from Address of the sender.
* @param to Address of the receiver.
* @param amount Amount of tokens to be approved.
*/
error ERC20TransferFailed(address from, address to, uint256 amount);
/**
* @dev Indicates a failure with the `amount` to be allocated.
* @param allocation The increase of circulating supply.
* @param totalSupply The total supply.
*/
error ERC20AllocationFailed(uint256 allocation, uint256 totalSupply);
}
iexchangeable.sol 55 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
interface IExchangeable {
/// @notice Sets the change authorization status to false
function removeEthExchangeAuthorization() external;
/// @notice Sets the change authorization status for a token to false
function removeExchangeAuthorizationForToken(address tokenToBeReceived) external;
/// @notice Sets whether the deposit of ETH against token is allowed or not
function setEthDepositExchangeRate(uint64 exchangeRate) external;
/// @notice Sets the ETH deposit authorization to false
function removeEthDepositAuthorization() external;
/// @notice Updates the exchange rate between ETH and the Token
function updateEthExchangeRate(uint64 exchangeRate) external;
/// @notice Updates the exchange rate between a token and our Token
/// @param tokenToBeReceived The token to be received in exchange of our Token
/// @param exchangeRate The exchange rate
function updateTokenExchangeRate(address tokenToBeReceived, uint64 exchangeRate) external;
/// @notice Returns the quantity of ETH available for change against Token
function getAvailableQuantityOfETH() external view returns(uint256);
/// @notice Returns the available quantity of a token to be exchanged
function getExchangeInfoForToken(address tokenToBeReceived) external view returns(bool, uint64);
/// @notice Returns the available quantity of a token to be exchanged against our Token
function getAvailableQuantityOfToken(address tokenToBeReceived) external returns(uint256);
/// @notice Enables a user to deposit ETH and receive Tokens in exchange
/// The conversion rate applies at a fixed rate, updated by Owner
function depositEther() external payable returns(uint256);
/// @notice Enables a user to sell back an amount of Tokens against ETH
/// if there is enough ETH available, and if the change is authorized
/// @param amountToken The amount of tokens to be exchanged
function sellBack(uint128 amountToken) external;
/// @notice Enables a user to sell back an amount of Tokens against a preferred token
/// if there is enough token available, and if the change is authorized
/// @param amountToken The amount of tokens to be exchanged
/// @param tokenToBeReceived The address of the token to be exchanged for
function sellBackAgainst(uint128 amountToken, address tokenToBeReceived) external;
/// @notice Enables the Owner to buy back tokens from a user, in exchange of ETH
/// and at a specified rate
/// @param from The beneficiary
/// @param amountToken The amount of tokens
/// @param rate The conversion rate
function buyBack(address payable from, uint128 amountToken, uint64 rate) external;
}
iowned.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
interface IOwned {
/// @notice Emitted when ownership of the contracted is transferred to a new owner
event OwnerChanged(uint indexed timestamp, address prevOwner, address newOwner);
/// @notice Returns the current owner of the contract
function owner() external view returns (address owner);
/// @notice Changes the ownership of the contract
/// @param newOwner The address of the new owner
function changeOwnership(address newOwner) external;
}
vestingschedule.sol 21 lines
// SPDX-License-Identifier: MIT
pragma solidity >= 0.8.20;
import { DurationUnits } from "../enums.sol";
struct VestingSchedule {
// beneficiary of tokens after they are released
address beneficiary;
// The upfront release when the vesting starts
uint8 upfrontRelease;
// start time of the vesting period
uint start;
// end of the vesting period in DurationUnits
uint end;
// the number of seconds between start and end
uint totalDuration;
// total amount of tokens to be released at the end of the vesting;
uint256 totalAmount;
// amount of tokens released
uint256 released;
}
Read Contract
ApprovedTokens 0x26947d2b → address
EthDepositIsAllowed 0x69dcf9e1 → bool
EthExchangeIsAllowed 0x0f4dd524 → bool
EthExchangeRate 0xf2e68dd1 → uint64
allowance 0xdd62ed3e → uint256
availableTokens 0x69bb4dc2 → uint256
balanceOf 0x70a08231 → uint256
cap 0x355274ea → uint256
circulatingSupply 0x9358928b → uint256
decimals 0x313ce567 → uint8
getApprovedTokens 0x6afc0c5f → address[]
getAvailableQuantityOfETH 0xabbb96ea → uint256
getCCIPAdmin 0x8fd6a6ac → address
getExchangeInfoForToken 0x1f520cd2 → bool, uint64
getReleasableAmount 0x8401b968 → uint256
getRemainingVestedAmount 0x6c89be01 → uint256
isChainIdAllowed 0x62d6a806 → bool
name 0x06fdde03 → string
owner 0x8da5cb5b → address
symbol 0x95d89b41 → string
totalSupply 0x18160ddd → uint256
Write Contract 29 functions
These functions modify contract state and require a wallet transaction to execute.
addApprovedToken 0x00d3794e
address token
uint8 decimals
allocate 0xb78b52df
address to
uint256 amount
allocateWithVesting 0x4b3271aa
address to
uint256 amount
uint256 cliffEnd
uint8 upfrontRelease
uint16 vestingDuration
uint8 vestingDurationUnit
allocateWithVesting 0x5417efff
address to
uint256 amount
uint16 cliffDuration
uint8 cliffDurationUnit
uint8 upfrontRelease
uint16 vestingDuration
uint8 vestingDurationUnit
allowlistDestinationChain 0x96d3b83d
uint64 _destinationChainSelector
bool allowed
approve 0x095ea7b3
address spender
uint256 value
returns: bool
burn 0x42966c68
uint256 amount
burn 0x9dc29fac
address account
uint256 amount
burnFrom 0x79cc6790
address account
uint256 amount
buyBack 0x648a5455
address from
uint128 amountToken
uint64 rate
changeDepositorStatus 0xb352fffe
address account
bool status
changeOwnership 0x2af4c31e
address newOwner
depositEther 0x98ea5fca
No parameters
returns: uint256
getAvailableQuantityOfToken 0x8c61caff
address tokenToBeReceived
returns: uint256
massAllocation 0x19d5fef8
address[] to
uint256[] amount
mint 0x40c10f19
address account
uint256 value
ownerTransfersBack 0xb2d8cd4b
uint256 amount
removeEthDepositAuthorization 0x487f24ae
No parameters
removeEthExchangeAuthorization 0x6c98faab
No parameters
removeExchangeAuthorizationForToken 0x52820bb3
address tokenToBeReceived
sellBack 0xb3eb2c66
uint128 amountToken
sellBackAgainst 0x5d3143fa
uint128 amountToken
address tokenToBeReceived
setCCIPAdmin 0xa8fa343c
address newAdmin
setEthDepositExchangeRate 0x29be2f8a
uint64 exchangeRate
transfer 0xa9059cbb
address to
uint256 value
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 value
returns: bool
unlockTransfers 0x21842be3
No parameters
updateEthExchangeRate 0xbcd135af
uint64 exchangeRate
updateTokenExchangeRate 0xb0f43e5f
address tokenToBeReceived
uint64 exchangeRate
Recent Transactions
No transactions found for this address