Address Contract Partially Verified
Address
0x6f38e0f1a73c96cB3f42598613EA3474F09cB200
Balance
0 ETH
Nonce
1
Code Size
10403 bytes
Creator
0xc6181D55...f23E at tx 0x81359241...1bdfce
Indexed Transactions
0
Contract Bytecode
10403 bytes
0x6080604052600436106102725760003560e01c806370a082311161014f578063a9059cbb116100c1578063d50256251161007a578063d5025625146106ed578063dcc7d4ad14610702578063dd62ed3e14610715578063de0e9a3e14610735578063eb470ebf14610755578063fcb79a7e1461077557610272565b8063a9059cbb14610633578063b40e80d114610653578063bf376c7a14610673578063c028df0614610693578063c45a0155146106a8578063c6788bdd146106bd57610272565b80639b56d6c9116101135780639b56d6c9146105895780639e4b5745146105a9578063a3ec1883146105be578063a457c2d7146105de578063a4c0ed36146105fe578063a78135871461061e57610272565b806370a082311461050a57806377e071ad1461052a5780637dc2cd981461054a5780638fd3ab801461055f57806395d89b411461057457610272565b8063313ce567116101e85780634000aea0116101ac5780634000aea01461046b57806342966c681461048b57806350e70d48146104ab57806360918117146104c05780636427ed97146104d55780636b03ed5f146104f557610272565b8063313ce567146103d457806332a7ae95146103f657806332bc320b14610416578063395093511461042b5780633bcc45ba1461044b57610272565b80631703a0181161023a5780631703a0181461033557806318160ddd1461034a5780631e3b9de51461035f57806323b872dd1461037f57806326773ddd1461039f5780632a0a4ed5146103bf57610272565b806306fdde03146102775780630832e470146102a2578063095ea7b3146102c45780630c6f0e5d146102f15780630cd865ec14610313575b600080fd5b34801561028357600080fd5b5061028c610795565b60405161029991906124d9565b60405180910390f35b3480156102ae57600080fd5b506102b76108f1565b6040516102999190612738565b3480156102d057600080fd5b506102e46102df366004612136565b6108f7565b6040516102999190612499565b3480156102fd57600080fd5b5061030661090d565b60405161029991906123d5565b34801561031f57600080fd5b5061033361032e366004612086565b61091c565b005b34801561034157600080fd5b506102b7610b2d565b34801561035657600080fd5b506102b7610b33565b34801561036b57600080fd5b5061030661037a366004612086565b610b39565b34801561038b57600080fd5b506102e461039a3660046120f6565b610b5a565b3480156103ab57600080fd5b506103336103ba3660046120be565b610bac565b3480156103cb57600080fd5b50610306610dca565b3480156103e057600080fd5b506103e9610e4c565b6040516102999190612741565b34801561040257600080fd5b50610333610411366004612086565b610e55565b34801561042257600080fd5b50610333611030565b34801561043757600080fd5b506102e4610446366004612136565b611056565b34801561045757600080fd5b50610306610466366004612086565b61108d565b34801561047757600080fd5b506102e4610486366004612161565b6110ae565b34801561049757600080fd5b506103336104a63660046122fe565b611131565b3480156104b757600080fd5b506103066111c4565b3480156104cc57600080fd5b506102b76111d3565b3480156104e157600080fd5b506103336104f03660046121e5565b6111d9565b34801561050157600080fd5b506103336111f8565b34801561051657600080fd5b506102b7610525366004612086565b611333565b34801561053657600080fd5b506102b7610545366004612086565b61134e565b34801561055657600080fd5b506102b7611424565b34801561056b57600080fd5b5061033361142a565b34801561058057600080fd5b5061028c6114c8565b34801561059557600080fd5b506102b76105a4366004612086565b61160b565b3480156105b557600080fd5b506102e4611629565b3480156105ca57600080fd5b506102e46105d9366004612086565b611630565b3480156105ea57600080fd5b506102e46105f9366004612136565b61164f565b34801561060a57600080fd5b50610333610619366004612161565b611686565b34801561062a57600080fd5b506102b76116ad565b34801561063f57600080fd5b506102e461064e366004612136565b6116b3565b34801561065f57600080fd5b506102e461066e366004612086565b6116c6565b34801561067f57600080fd5b5061033361068e366004612136565b6116db565b34801561069f57600080fd5b50610306611778565b3480156106b457600080fd5b50610306611787565b3480156106c957600080fd5b506106dd6106d8366004612086565b611796565b604051610299949392919061246e565b3480156106f957600080fd5b5061028c6117c8565b61033361071036600461221d565b611856565b34801561072157600080fd5b506102b76107303660046120be565b611a0d565b34801561074157600080fd5b506103336107503660046122fe565b611a38565b34801561076157600080fd5b506102b7610770366004612086565b611a5a565b34801561078157600080fd5b506103336107903660046120be565b611a78565b606061079f611629565b1561085457600960009054906101000a90046001600160a01b03166001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b1580156107f257600080fd5b505afa158015610806573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261082e9190810190612255565b60405160200161083e9190612373565b60405160208183030381529060405290506108ee565b600960009054906101000a90046001600160a01b03166001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b1580156108a257600080fd5b505afa1580156108b6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108de9190810190612255565b60405160200161083e91906123a5565b90565b600b5481565b6000610904338484611aad565b50600192915050565b6007546001600160a01b031681565b6001600160a01b03808216600090815260056020908152604091829020825160808101845281548516815260018201549281018390526002820154938101939093526003015490921660608201819052909190816109955760405162461bcd60e51b815260040161098c906125d3565b60405180910390fd5b82516001600160a01b031633146109be5760405162461bcd60e51b815260040161098c9061250c565b4260045484604001516109d1919061274f565b11156109ef5760405162461bcd60e51b815260040161098c90612543565b82516001600160a01b0380861660009081526005602052604080822080546001600160a01b0319908116825560018201849055600282019390935560030180549092169091555163a9059cbb60e01b81529083169063a9059cbb90610a5a908490879060040161240d565b602060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aac9190612201565b610ac85760405162461bcd60e51b815260040161098c906125fb565b610adb8582610ad688611333565b611b08565b806001600160a01b0316856001600160a01b03167f52a5c2b28bc6eb9712d0ced43463103b486b13ccc9cda499fd3b2d7b6a74a8ee85604051610b1e9190612738565b60405180910390a35050505050565b600d5481565b60025490565b6001600160a01b03808216600090815260056020526040902054165b919050565b6000610b67848484611b08565b6001600160a01b038416600090815260016020908152604080832033808552925290912054610ba2918691610b9d9086906127a6565b611aad565b5060019392505050565b610bb581611630565b610bd15760405162461bcd60e51b815260040161098c90612632565b6000610bdc8361134e565b905060008111610bfe5760405162461bcd60e51b815260040161098c906125a3565b336000610c0a84611333565b90506000610c188483612787565b90508582610c385760405162461bcd60e51b815260040161098c906126ca565b6001600160a01b03861660009081526005602052604090206001015415610c715760405162461bcd60e51b815260040161098c90612667565b6040516323b872dd60e01b81526001600160a01b038216906323b872dd90610ca1908790309087906004016123e9565b602060405180830381600087803b158015610cbb57600080fd5b505af1158015610ccf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cf39190612201565b610d0f5760405162461bcd60e51b815260040161098c906125fb565b604080516080810182526001600160a01b038087168083526020808401878152428587019081528d8516606087019081528d86166000818152600590955293889020965187549087166001600160a01b0319918216178855925160018801559051600287015551600390950180549590941694169390931790915591517f1982ca8958fc8a8176cb52be509260f4bc5af7ce04e1533711793f1c56dd535990610db9908790612738565b60405180910390a350505050505050565b60095460408051632a0a4ed560e01b815290516000926001600160a01b031691632a0a4ed5916004808301926020929190829003018186803b158015610e0f57600080fd5b505afa158015610e23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e4791906120a2565b905090565b60035460ff1681565b610e5d610dca565b6001600160a01b0316336001600160a01b031614610e8d5760405162461bcd60e51b815260040161098c90612701565b6001600160a01b038082166000908152600560209081526040918290208251608081018452815485168152600182015492810183905260028201549381019390935260030154909216606082018190529091610efb5760405162461bcd60e51b815260040161098c906125d3565b6001600160a01b03808416600090815260056020908152604080832080546001600160a01b031990811682556001820185905560028201949094556003018054909316909255845190850151915163a9059cbb60e01b81529284169263a9059cbb92610f6a929160040161240d565b602060405180830381600087803b158015610f8457600080fd5b505af1158015610f98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fbc9190612201565b610fd85760405162461bcd60e51b815260040161098c906125fb565b81600001516001600160a01b0316836001600160a01b03167fbb036e629a9f4c0897ee5d48440dfdb36f7e772117723a2ed603a6514244c2d584602001516040516110239190612738565b60405180910390a3505050565b600c546001600160a01b031633141561105457600c80546001600160a01b03191690555b565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091610904918590610b9d90869061274f565b6001600160a01b039081166000908152600560205260409020600301541690565b6000806110bb86866116b3565b9050801561112857604051635260769b60e11b81526001600160a01b0387169063a4c0ed36906110f5903390899089908990600401612426565b600060405180830381600087803b15801561110f57600080fd5b505af1158015611123573d6000803e3d6000fd5b505050505b95945050505050565b61113b3382611bc5565b6000611145611629565b61115157600b54611154565b60015b6009549091506001600160a01b03166342966c686111728385612787565b6040518263ffffffff1660e01b815260040161118e9190612738565b600060405180830381600087803b1580156111a857600080fd5b505af11580156111bc573d6000803e3d6000fd5b505050505050565b6009546001600160a01b031681565b60085481565b336000908152600660205260409020805460ff19169115919091179055565b3360009081526005602052604090206001015415611054573360008181526005602052604080822060018101805460038301805484546001600160a01b0319908116865593879055600290940195909555908216909355905163a9059cbb60e01b815291926001600160a01b0390911691829163a9059cbb916112809190869060040161240d565b602060405180830381600087803b15801561129a57600080fd5b505af11580156112ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d29190612201565b6112ee5760405162461bcd60e51b815260040161098c906125fb565b336001600160a01b03167f203627483d943880619f4b7e0cca21dbefd6204b4d85b124eb99540e17ba86dd836040516113279190612738565b60405180910390a25050565b6001600160a01b031660009081526020819052604090205490565b60008061135a83611c5f565b90508015611369579050610b55565b6009546001600160a01b0384811691161415611389575050600b54610b55565b600b546009546040516377e071ad60e01b81526001600160a01b03909116906377e071ad906113bc9087906004016123d5565b60206040518083038186803b1580156113d457600080fd5b505afa1580156113e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140c9190612316565b6114169190612787565b915050610b55565b50919050565b60045481565b33611433611ca1565b1561143d57600080fd5b611445610b33565b61145190611f40612787565b61145a82611333565b61146690612710612787565b10156114845760405162461bcd60e51b815260040161098c9061269e565b61148e8182611cb2565b7f3b6b79a09e9fd230e8591b65c97236bf7df7a604edf733db0658e66b0e6eb2a9816040516114bd91906123d5565b60405180910390a150565b60606114d2611629565b1561157157600960009054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b15801561152557600080fd5b505afa158015611539573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115619190810190612255565b60405160200161083e919061232e565b600960009054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b1580156115bf57600080fd5b505afa1580156115d3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526115fb9190810190612255565b60405160200161083e9190612357565b6001600160a01b031660009081526005602052604090206001015490565b600b541590565b6001600160a01b031660009081526006602052604090205460ff161590565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091610904918590610b9d9086906127a6565b6009546001600160a01b0316331461169d57600080fd5b6116a78484611e7a565b50505050565b600e5481565b60006116bf8383611f1b565b9392505050565b60066020526000908152604090205460ff1681565b6009546040516323b872dd60e01b81526001600160a01b03909116906323b872dd9061170f903390309086906004016123e9565b602060405180830381600087803b15801561172957600080fd5b505af115801561173d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117619190612201565b61176a57600080fd5b6117748282611e7a565b5050565b600c546001600160a01b031681565b600a546001600160a01b031681565b60056020526000908152604090208054600182015460028301546003909301546001600160a01b039283169391921684565b600f80546117d5906127e9565b80601f0160208091040260200160405190810160405280929190818152602001828054611801906127e9565b801561184e5780601f106118235761010080835404028352916020019161184e565b820191906000526020600020905b81548152906001019060200180831161183157829003601f168201915b505050505081565b61185e611629565b61186757600080fd5b600a54600d54600e54604051634dc5e43160e01b81526000936001600160a01b031692634dc5e4319234926118a8928a9233928b928b9290916004016124a4565b6020604051808303818588803b1580156118c157600080fd5b505af11580156118d5573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906118fa91906120a2565b9050611904611ca1565b156119e857806001600160a01b0316633f5e3e7f6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561194457600080fd5b505af1158015611958573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197c9190612201565b61198557600080fd5b600c546040516306a169ed60e01b81526001600160a01b03909116906306a169ed906119b59084906004016123d5565b600060405180830381600087803b1580156119cf57600080fd5b505af11580156119e3573d6000803e3d6000fd5b505050505b600c80546001600160a01b0319166001600160a01b0392909216919091179055505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b611a40611629565b15611a4a57600080fd5b611a573382600b54611f4b565b50565b6001600160a01b031660009081526005602052604090206002015490565b600c546001600160a01b03163314611a8f57600080fd5b611aa382611a9c84611333565b6001611f4b565b6117748183611cb2565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590611023908590612738565b6001600160a01b038216611b1b57600080fd5b611b26838383611fee565b6001600160a01b03831660009081526020819052604081208054839290611b4e9084906127a6565b90915550506001600160a01b03821660009081526020819052604081208054839290611b7b90849061274f565b92505081905550816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516110239190612738565b611bd182600083611fee565b8060026000828254611be391906127a6565b90915550506001600160a01b03821660009081526020819052604081208054839290611c109084906127a6565b90915550506040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c53908590612738565b60405180910390a35050565b60006001600160a01b038216301415611c7a57506001610b55565b6007546001600160a01b0383811691161415611c995750600854610b55565b506000610b55565b600c546001600160a01b0316151590565b611cba611629565b611cc357600080fd5b6009546040516370a0823160e01b81526001600160a01b039091169063a9059cbb90839083906370a0823190611cfd9030906004016123d5565b60206040518083038186803b158015611d1557600080fd5b505afa158015611d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d4d9190612316565b6040518363ffffffff1660e01b8152600401611d6a92919061240d565b602060405180830381600087803b158015611d8457600080fd5b505af1158015611d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dbc9190612201565b611dc557600080fd5b600980546001600160a01b0319166001600160a01b038416179055611774611deb610b33565b6009546040516370a0823160e01b81526001600160a01b03909116906370a0823190611e1b9030906004016123d5565b60206040518083038186803b158015611e3357600080fd5b505afa158015611e47573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6b9190612316565b611e759190612767565b612066565b6001600160a01b038216611e8d57600080fd5b611e9960008383611fee565b8060026000828254611eab919061274f565b90915550506001600160a01b03821660009081526020819052604081208054839290611ed890849061274f565b90915550506040516001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c53908590612738565b6000611f278383612079565b611f435760405162461bcd60e51b815260040161098c9061257a565b6109046111f8565b611f558383611bc5565b6009546001600160a01b031663a9059cbb84611f718486612787565b6040518363ffffffff1660e01b8152600401611f8e92919061240d565b602060405180830381600087803b158015611fa857600080fd5b505af1158015611fbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fe09190612201565b611fe957600080fd5b505050565b611ff6611ca1565b15611fe957600c5460405163e1a1810f60e01b81526001600160a01b039091169063e1a1810f9061202f908690869086906004016123e9565b600060405180830381600087803b15801561204957600080fd5b505af115801561205d573d6000803e3d6000fd5b50505050505050565b600181101561207457600080fd5b600b55565b6000610904338484611b08565b600060208284031215612097578081fd5b81356116bf8161284a565b6000602082840312156120b3578081fd5b81516116bf8161284a565b600080604083850312156120d0578081fd5b82356120db8161284a565b915060208301356120eb8161284a565b809150509250929050565b60008060006060848603121561210a578081fd5b83356121158161284a565b925060208401356121258161284a565b929592945050506040919091013590565b60008060408385031215612148578182fd5b82356121538161284a565b946020939093013593505050565b60008060008060608587031215612176578081fd5b84356121818161284a565b935060208501359250604085013567ffffffffffffffff808211156121a4578283fd5b818701915087601f8301126121b7578283fd5b8135818111156121c5578384fd5b8860208285010111156121d6578384fd5b95989497505060200194505050565b6000602082840312156121f6578081fd5b81356116bf8161285f565b600060208284031215612212578081fd5b81516116bf8161285f565b600080600060608486031215612231578283fd5b8335925060208401359150604084013561224a8161284a565b809150509250925092565b600060208284031215612266578081fd5b815167ffffffffffffffff8082111561227d578283fd5b818401915084601f830112612290578283fd5b8151818111156122a2576122a2612834565b604051601f8201601f19908116603f011681019083821181831017156122ca576122ca612834565b816040528281528760208487010111156122e2578586fd5b6122f38360208301602088016127bd565b979650505050505050565b60006020828403121561230f578081fd5b5035919050565b600060208284031215612327578081fd5b5051919050565b6000601160fa1b8252825161234a8160018501602087016127bd565b9190910160010192915050565b6000605760f81b8252825161234a8160018501602087016127bd565b6000690223930b3b3b0b13632960b51b8252825161239881600a8501602087016127bd565b91909101600a0192915050565b60006702bb930b83832b2160c51b825282516123c88160088501602087016127bd565b9190910160080192915050565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b0385168152602081018490526060604082018190528101829052600082846080840137818301608090810191909152601f909201601f191601019392505050565b6001600160a01b03948516815260208101939093526040830191909152909116606082015260800190565b901515815260200190565b9586526001600160a01b039485166020870152604086019390935292166060840152608083019190915260a082015260c00190565b60006020825282518060208401526124f88160408501602087016127bd565b601f01601f19169190910160400192915050565b6020808252601f908201527f4f6e6c7920636c61696d616e742063616e207265736f6c766520636c61696d00604082015260600190565b60208082526019908201527f436c61696d20706572696f64206e6f74206f7665722079657400000000000000604082015260600190565b6020808252600f908201526e151c985b9cd9995c8819985a5b1959608a1b604082015260600190565b602080825260169082015275155b9cdd5c1c1bdc9d19590818dbdb1b185d195c985b60521b604082015260600190565b6020808252600e908201526d139bc818db185a5b48199bdd5b9960921b604082015260600190565b6020808252601a908201527f436f6c6c61746572616c207472616e73666572206661696c6564000000000000604082015260600190565b6020808252818101527f436c61696d732064697361626c656420666f7220746869732061646472657373604082015260600190565b60208082526017908201527f4164647265737320616c726561647920636c61696d6564000000000000000000604082015260600190565b602080825260129082015271145d5bdc9d5b481b9bdd081c995858da195960721b604082015260600190565b6020808252601f908201527f436c61696d6564206164647265737320686f6c6473206e6f2073686172657300604082015260600190565b60208082526018908201527f596f752063616e6e6f742064656c65746520636c61696d730000000000000000604082015260600190565b90815260200190565b60ff91909116815260200190565b600082198211156127625761276261281e565b500190565b60008261278257634e487b7160e01b81526012600452602481fd5b500490565b60008160001904831182151516156127a1576127a161281e565b500290565b6000828210156127b8576127b861281e565b500390565b60005b838110156127d85781810151838201526020016127c0565b838111156116a75750506000910152565b6002810460018216806127fd57607f821691505b6020821081141561141e57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611a5757600080fd5b8015158114611a5757600080fdfea2646970667358221220d0f14521c293fe962159c01fb4a60e9f1b718f0e199f1b629f370472c2098d9664736f6c63430008010033
Verified Source Code Partial Match
Compiler: v0.8.1+commit.df193b15
EVM: istanbul
Optimization: Yes (200 runs)
ERC20.sol 258 lines
// SPDX-License-Identifier: MIT
// Copied and adjusted from OpenZeppelin
// Adjustments:
// - modifications to support ERC-677
// - removed require messages to save space
// - removed unnecessary require statements
// - removed GSN Context
// - upgraded to 0.8 to drop SafeMath
// - let name() and symbol() be implemented by subclass
pragma solidity >=0.8;
import "./IERC20.sol";
import "./IERC677Receiver.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`.
* For a generic mechanism see `ERC20Mintable`.
*
* *For a detailed writeup see our guide [How to implement supply
* mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an `Approval` event is emitted on calls to `transferFrom`.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
* functions have been added to mitigate the well-known issues around setting
* allowances. See `IERC20.approve`.
*/
abstract contract ERC20 is IERC20 {
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
uint8 public override decimals;
constructor(uint8 _decimals) {
decimals = _decimals;
}
/**
* @dev See `IERC20.totalSupply`.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See `IERC20.balanceOf`.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See `IERC20.transfer`.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(msg.sender, recipient, amount);
return true;
}
/**
* @dev See `IERC20.allowance`.
*/
function allowance(address owner, address spender) public view override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See `IERC20.approve`.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public override returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
/**
* @dev See `IERC20.transferFrom`.
*
* Emits an `Approval` event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of `ERC20`;
*
* Requirements:
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `value`.
* - the caller must have allowance for `sender`'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, msg.sender, _allowances[sender][msg.sender] - amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to `approve` that can be used as a mitigation for
* problems described in `IERC20.approve`.
*
* Emits an `Approval` event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(msg.sender, spender, _allowances[msg.sender][spender] - subtractedValue);
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to `transfer`, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a `Transfer` event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(recipient != address(0));
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] -= amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
// ERC-677 functionality, can be useful for swapping and wrapping tokens
function transferAndCall(address recipient, uint amount, bytes calldata data) public returns (bool) {
bool success = transfer(recipient, amount);
if (success){
IERC677Receiver(recipient).onTokenTransfer(msg.sender, amount, data);
}
return success;
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a `Transfer` event with `from` set to the zero address.
*
* Requirements
*
* - `to` cannot be the zero address.
*/
function _mint(address recipient, uint256 amount) internal virtual {
require(recipient != address(0));
_beforeTokenTransfer(address(0), recipient, amount);
_totalSupply += amount;
_balances[recipient] += amount;
emit Transfer(address(0), recipient, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a `Transfer` event with `to` set to the zero address.
*
* Requirements
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
_beforeTokenTransfer(account, address(0), amount);
_totalSupply -= amount;
_balances[account] -= amount;
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
*
* This is 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.
*/
function _approve(address owner, address spender, uint256 value) internal {
_allowances[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) virtual internal;
}
IERC20.sol 91 lines
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2016-2019 zOS Global Limited
*
*/
pragma solidity >=0.8;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
// Optional functions
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
/**
* @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.
*
* > 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);
}
ERC20Draggable.sol 210 lines
/** * SPDX-License-Identifier: LicenseRef-Aktionariat * * MIT License with Automated License Fee Payments * * Copyright (c) 2020 Aktionariat AG (aktionariat.com) * * Permission is hereby granted to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - All automated license fee payments integrated into this and related Software * are preserved. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity >=0.8; /** * @title CompanyName Shareholder Agreement * @author Luzius Meisser, [email protected] * @dev These tokens are based on the ERC20 standard and the open-zeppelin library. * * This is an ERC-20 token representing shares of CompanyName AG that are bound to * a shareholder agreement that can be found at the URL defined in the constant 'terms' * of the 'DraggableCompanyNameShares' contract. The agreement is partially enforced * through the Swiss legal system, and partially enforced through this smart contract. * In particular, this smart contract implements a drag-along clause which allows the * majority of token holders to force the minority sell their shares along with them in * case of an acquisition. That's why the tokens are called "Draggable CompanyName AG Shares." */ import "./ERC20.sol"; import "./IERC20.sol"; import "./IERC677Receiver.sol"; contract ERC20Draggable is ERC20, IERC677Receiver { IERC20 public wrapped; // The wrapped contract IOfferFactory public factory; // If the wrapped tokens got replaced in an acquisition, unwrapping might yield many currency tokens uint256 public unwrapConversionFactor = 0; // The current acquisition attempt, if any. See initiateAcquisition to see the requirements to make a public offer. IOffer public offer; uint256 public quorum; uint256 public votePeriod; event MigrationSucceeded(address newContractAddress); constructor( address offerFactory, address wrappedToken, uint256 quorum_, uint256 votePeriod_ ) ERC20(0) { factory = IOfferFactory(offerFactory); wrapped = IERC20(wrappedToken); quorum = quorum_; votePeriod = votePeriod_; } function name() public override view returns (string memory){ if (isBinding()){ return string(abi.encodePacked("Draggable ", wrapped.name())); } else { return string(abi.encodePacked("Wrapped ", wrapped.name())); } } function symbol() public override view returns (string memory){ if (isBinding()){ return string(abi.encodePacked("D", wrapped.symbol())); } else { return string(abi.encodePacked("W", wrapped.symbol())); } } function onTokenTransfer(address from, uint256 amount, bytes calldata) override public { require(msg.sender == address(wrapped)); _mint(from, amount); } /** Increases the number of drag-along tokens. Requires minter to deposit an equal amount of share tokens */ function wrap(address shareholder, uint256 amount) public { require(wrapped.transferFrom(msg.sender, address(this), amount)); _mint(shareholder, amount); } /** * Indicates that the token holders are bound to the token terms and that: * - Conversions back to the wrapped token (unwrap) are not allowed * - The drag-along can be performed by making an according offer * - They can be migrated to a new version of this contract in accordance with the terms */ function isBinding() public view returns (bool) { return unwrapConversionFactor == 0; } /** * Deactivates the drag-along mechanism and enables the unwrap function. */ function deactivate(uint256 factor) internal { require(factor >= 1); unwrapConversionFactor = factor; } /** Decrease the number of drag-along tokens. The user gets back their shares in return */ function unwrap(uint256 amount) public { require(!isBinding()); unwrap(msg.sender, amount, unwrapConversionFactor); } function unwrap(address owner, uint256 amount, uint256 factor) internal { _burn(owner, amount); require(wrapped.transfer(owner, amount * factor)); } /** * Burns both the token itself as well as the wrapped token! * If you want to get out of the shareholder agreement, use unwrap after it has been * deactivated by a majority vote or acquisition. * * Burning only works if wrapped token supports burning. Also, the exact meaning of this * operation might depend on the circumstances. Burning and reussing the wrapped token * does not free the sender from the legal obligations of the shareholder agreement. */ function burn(uint256 amount) public { _burn(msg.sender, amount); uint256 factor = isBinding() ? 1 : unwrapConversionFactor; IBurnable(address(wrapped)).burn(amount * factor); } function makeAcquisitionOffer(bytes32 salt, uint256 pricePerShare, address currency) public payable { require(isBinding()); address newOffer = factory.create{value: msg.value}(salt, msg.sender, pricePerShare, currency, quorum, votePeriod); if (offerExists()) { require(IOffer(newOffer).isWellFunded()); offer.contest(newOffer); } offer = IOffer(newOffer); } function drag(address buyer, address currency) public { require(msg.sender == address(offer)); unwrap(buyer, balanceOf(buyer), 1); replaceWrapped(currency, buyer); } function notifyOfferEnded() public { if (msg.sender == address(offer)){ offer = IOffer(address(0)); } } function replaceWrapped(address newWrapped, address oldWrappedDestination) internal { require(isBinding()); // Free all old wrapped tokens we have require(wrapped.transfer(oldWrappedDestination, wrapped.balanceOf(address(this)))); // Count the new wrapped tokens wrapped = IERC20(newWrapped); deactivate(wrapped.balanceOf(address(this)) / totalSupply()); } function migrate() public { address successor = msg.sender; require(!offerExists()); // if you have 80%, you can easily cancel the offer first if necessary require(balanceOf(successor) * 10000 >= totalSupply() * 8000, "Quorum not reached"); replaceWrapped(successor, successor); emit MigrationSucceeded(successor); } function _beforeTokenTransfer(address from, address to, uint256 amount) override internal { if (offerExists()) { offer.notifyMoved(from, to, amount); } } function offerExists() internal view returns (bool) { return address(offer) != address(0); } } abstract contract IBurnable { function burn(uint256) virtual public; } abstract contract IOffer { function isWellFunded() virtual public returns (bool); function contest(address newOffer) virtual public; function notifyMoved(address from, address to, uint256 value) virtual public; } abstract contract IOfferFactory { function create(bytes32 salt, address buyer, uint256 pricePerShare, address currency, uint256 quorum, uint256 votePeriod) virtual public payable returns (address); }
DraggableShares.sol 96 lines
/** * SPDX-License-Identifier: LicenseRef-Aktionariat * * MIT License with Automated License Fee Payments * * Copyright (c) 2020 Aktionariat AG (aktionariat.com) * * Permission is hereby granted to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * - The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * - All automated license fee payments integrated into this and related Software * are preserved. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ pragma solidity >=0.8; import "./ERC20Recoverable.sol"; import "./ERC20Draggable.sol"; /** * @title Draggable CompanyName AG Shares * @author Luzius Meisser, [email protected] * * This is an ERC-20 token representing shares of CompanyName AG that are bound to * a shareholder agreement that can be found at the URL defined in the constant 'terms'. * The shareholder agreement is partially enforced through this smart contract. The agreement * is designed to facilitate a complete acquisition of the firm even if a minority of shareholders * disagree with the acquisition, to protect the interest of the minority shareholders by requiring * the acquirer to offer the same conditions to everyone when acquiring the company, and to * facilitate an update of the shareholder agreement even if a minority of the shareholders that * are bound to this agreement disagree. The name "draggable" stems from the convention of calling * the right to drag a minority along with a sale of the company "drag-along" rights. The name is * chosen to ensure that token holders are aware that they are bound to such an agreement. * * The percentage of token holders that must agree with an update of the terms is defined by the * constant UPDATE_QUORUM. The percentage of yes-votes that is needed to successfully complete an * acquisition is defined in the constant ACQUISITION_QUORUM. Note that the update quorum is based * on the total number of tokens in circulation. In contrast, the acquisition quorum is based on the * number of votes cast during the voting period, not taking into account those who did not bother * to vote. */ contract DraggableShares is ERC20Recoverable, ERC20Draggable { string public terms; /** * Designed to be used with the Crypto Franc as currency token. See also parent constructor. */ constructor(string memory _terms, address offerFactory, address wrappedToken, uint256 quorum, uint256 votePeriod) ERC20Draggable(offerFactory, wrappedToken, quorum, votePeriod) { IRecoverable(wrappedToken).setRecoverable(false); terms = _terms; // to update the terms, migrate to a new contract. That way it is ensured that the terms can only be updated when the quorom agrees. } function transfer(address to, uint256 value) override(ERC20Recoverable, ERC20) public returns (bool) { return super.transfer(to, value); } function getClaimDeleter() public view override returns (address) { return IRecoverable(address(wrapped)).getClaimDeleter(); } function getCollateralRate(address collateralType) public view override returns (uint256) { uint256 rate = super.getCollateralRate(collateralType); if (rate > 0) { return rate; } else if (collateralType == address(wrapped)) { return unwrapConversionFactor; } else { // If the wrapped contract allows for a specific collateral, we should too. // If the wrapped contract is not IRecoverable, we will fail here, but would fail anyway. return IRecoverable(address(wrapped)).getCollateralRate(collateralType) * unwrapConversionFactor; } } } abstract contract IRecoverable { function setRecoverable(bool) public virtual; function getCollateralRate(address) public virtual view returns (uint256); function getClaimDeleter() public virtual view returns (address); }
IERC677Receiver.sol 9 lines
// SPDX-License-Identifier: MIT
// Copied from https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/UniswapV2Router02.sol
pragma solidity >=0.8;
interface IERC677Receiver {
function onTokenTransfer(address from, uint256 amount, bytes calldata data) external;
}
ERC20Recoverable.sol 239 lines
/**
* SPDX-License-Identifier: LicenseRef-Aktionariat
*
* MIT License with Automated License Fee Payments
*
* Copyright (c) 2020 Aktionariat AG (aktionariat.com)
*
* Permission is hereby granted to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - All automated license fee payments integrated into this and related Software
* are preserved.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
pragma solidity >=0.8;
import "./ERC20.sol";
import "./IERC20.sol";
/**
* @title Recoverable
* In case of tokens that represent real-world assets such as shares of a company, one needs a way
* to handle lost private keys. With physical certificates, courts can declare share certificates as
* invalid so the company can issue replacements. Here, we want a solution that does not depend on
* third parties to resolve such cases. Instead, when someone has lost a private key, he can use the
* declareLost function to post a deposit and claim that the shares assigned to a specific address are
* lost. To prevent front running, a commit reveal scheme is used. If he actually is the owner of the shares,
* he needs to wait for a certain period and can then reclaim the lost shares as well as the deposit.
* If he is an attacker trying to claim shares belonging to someone else, he risks losing the deposit
* as it can be claimed at anytime by the rightful owner.
* Furthermore, if "getClaimDeleter" is defined in the subclass, the returned address is allowed to
* delete claims, returning the collateral. This can help to prevent obvious cases of abuse of the claim
* function.
*/
abstract contract ERC20Recoverable is ERC20 {
// A struct that represents a claim made
struct Claim {
address claimant; // the person who created the claim
uint256 collateral; // the amount of collateral deposited
uint256 timestamp; // the timestamp of the block in which the claim was made
address currencyUsed; // The currency (XCHF) can be updated, we record the currency used for every request
}
uint256 public claimPeriod = 180 days; // Default of 180 days;
mapping(address => Claim) public claims; // there can be at most one claim per address, here address is claimed address
mapping(address => bool) public recoveryDisabled; // disable claimability (e.g. for long term storage)
// ERC-20 token that can be used as collateral or 0x0 if disabled
address public customCollateralAddress;
uint256 public customCollateralRate;
/**
* Returns the collateral rate for the given collateral type and 0 if that type
* of collateral is not accepted. By default, only the token itself is accepted at
* a rate of 1:1.
*
* Subclasses should override this method if they want to add additional types of
* collateral.
*/
function getCollateralRate(address collateralType) public virtual view returns (uint256) {
if (collateralType == address(this)) {
return 1;
} else if (collateralType == customCollateralAddress) {
return customCollateralRate;
} else {
return 0;
}
}
/**
* Allows subclasses to set a custom collateral besides the token itself.
* The collateral must be an ERC-20 token that returns true on successful transfers and
* throws an exception or returns false on failure.
* Also, do not forget to multiply the rate in accordance with the number of decimals of the collateral.
* For example, rate should be 7*10**18 for 7 units of a collateral with 18 decimals.
*/
function _setCustomClaimCollateral(address collateral, uint256 rate) internal {
customCollateralAddress = collateral;
if (customCollateralAddress == address(0)) {
customCollateralRate = 0; // disabled
} else {
require(rate > 0, "Collateral rate can't be zero");
customCollateralRate = rate;
}
emit CustomClaimCollateralChanged(collateral, rate);
}
function getClaimDeleter() virtual public view returns (address);
/**
* Allows subclasses to change the claim period, but not to fewer than 90 days.
*/
function _setClaimPeriod(uint256 claimPeriodInDays) internal {
require(claimPeriodInDays > 90, "Claim period must be at least 90 days"); // must be at least 90 days
uint256 claimPeriodInSeconds = claimPeriodInDays * (1 days);
claimPeriod = claimPeriodInSeconds;
emit ClaimPeriodChanged(claimPeriod);
}
function setRecoverable(bool enabled) public {
recoveryDisabled[msg.sender] = !enabled;
}
/**
* Some users might want to disable claims for their address completely.
* For example if they use a deep cold storage solution or paper wallet.
*/
function isRecoveryEnabled(address target) public view returns (bool) {
return !recoveryDisabled[target];
}
event ClaimMade(address indexed lostAddress, address indexed claimant, uint256 balance);
event ClaimCleared(address indexed lostAddress, uint256 collateral);
event ClaimDeleted(address indexed lostAddress, address indexed claimant, uint256 collateral);
event ClaimResolved(address indexed lostAddress, address indexed claimant, uint256 collateral);
event ClaimPeriodChanged(uint256 newClaimPeriodInDays);
event CustomClaimCollateralChanged(address newCustomCollateralAddress, uint256 newCustomCollareralRate);
/** Anyone can declare that the private key to a certain address was lost by calling declareLost
* providing a deposit/collateral. There are three possibilities of what can happen with the claim:
* 1) The claim period expires and the claimant can get the deposit and the shares back by calling recover
* 2) The "lost" private key is used at any time to call clearClaim. In that case, the claim is deleted and
* the deposit sent to the shareholder (the owner of the private key). It is recommended to call recover
* whenever someone transfers funds to let claims be resolved automatically when the "lost" private key is
* used again.
* 3) The owner deletes the claim and assigns the deposit to the claimant. This is intended to be used to resolve
* disputes. Generally, using this function implies that you have to trust the issuer of the tokens to handle
* the situation well. As a rule of thumb, the contract owner should assume the owner of the lost address to be the
* rightful owner of the deposit.
* It is highly recommended that the owner observes the claims made and informs the owners of the claimed addresses
* whenever a claim is made for their address (this of course is only possible if they are known to the owner, e.g.
* through a shareholder register).
*/
function declareLost(address collateralType, address lostAddress) public {
require(isRecoveryEnabled(lostAddress), "Claims disabled for this address");
uint256 collateralRate = getCollateralRate(collateralType);
require(collateralRate > 0, "Unsupported collateral");
address claimant = msg.sender;
uint256 balance = balanceOf(lostAddress);
uint256 collateral = balance * collateralRate;
IERC20 currency = IERC20(collateralType);
require(balance > 0, "Claimed address holds no shares");
require(claims[lostAddress].collateral == 0, "Address already claimed");
require(currency.transferFrom(claimant, address(this), collateral), "Collateral transfer failed");
claims[lostAddress] = Claim({
claimant: claimant,
collateral: collateral,
timestamp: block.timestamp,
currencyUsed: collateralType
});
emit ClaimMade(lostAddress, claimant, balance);
}
function getClaimant(address lostAddress) public view returns (address) {
return claims[lostAddress].claimant;
}
function getCollateral(address lostAddress) public view returns (uint256) {
return claims[lostAddress].collateral;
}
function getCollateralType(address lostAddress) public view returns (address) {
return claims[lostAddress].currencyUsed;
}
function getTimeStamp(address lostAddress) public view returns (uint256) {
return claims[lostAddress].timestamp;
}
function transfer(address recipient, uint256 amount) override virtual public returns (bool) {
require(super.transfer(recipient, amount), "Transfer failed");
clearClaim();
return true;
}
/**
* Clears a claim after the key has been found again and assigns the collateral to the "lost" address.
* This is the price an adverse claimer pays for filing a false claim and makes it risky to do so.
*/
function clearClaim() public {
if (claims[msg.sender].collateral != 0) {
uint256 collateral = claims[msg.sender].collateral;
IERC20 currency = IERC20(claims[msg.sender].currencyUsed);
delete claims[msg.sender];
require(currency.transfer(msg.sender, collateral), "Collateral transfer failed");
emit ClaimCleared(msg.sender, collateral);
}
}
/**
* After the claim period has passed, the claimant can call this function to send the
* tokens on the lost address as well as the collateral to himself.
*/
function recover(address lostAddress) public {
Claim memory claim = claims[lostAddress];
uint256 collateral = claim.collateral;
IERC20 currency = IERC20(claim.currencyUsed);
require(collateral != 0, "No claim found");
require(claim.claimant == msg.sender, "Only claimant can resolve claim");
require(claim.timestamp + claimPeriod <= block.timestamp, "Claim period not over yet");
address claimant = claim.claimant;
delete claims[lostAddress];
require(currency.transfer(claimant, collateral), "Collateral transfer failed");
_transfer(lostAddress, claimant, balanceOf(lostAddress));
emit ClaimResolved(lostAddress, claimant, collateral);
}
/**
* This function is to be executed by the claim deleter only in case a dispute needs to be resolved manually.
*/
function deleteClaim(address lostAddress) public {
require(msg.sender == getClaimDeleter(), "You cannot delete claims");
Claim memory claim = claims[lostAddress];
IERC20 currency = IERC20(claim.currencyUsed);
require(claim.collateral != 0, "No claim found");
delete claims[lostAddress];
require(currency.transfer(claim.claimant, claim.collateral), "Collateral transfer failed");
emit ClaimDeleted(lostAddress, claim.claimant, claim.collateral);
}
}
Read Contract
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
claimPeriod 0x7dc2cd98 → uint256
claims 0xc6788bdd → address, uint256, uint256, address
customCollateralAddress 0x0c6f0e5d → address
customCollateralRate 0x60918117 → uint256
decimals 0x313ce567 → uint8
factory 0xc45a0155 → address
getClaimDeleter 0x2a0a4ed5 → address
getClaimant 0x1e3b9de5 → address
getCollateral 0x9b56d6c9 → uint256
getCollateralRate 0x77e071ad → uint256
getCollateralType 0x3bcc45ba → address
getTimeStamp 0xeb470ebf → uint256
isBinding 0x9e4b5745 → bool
isRecoveryEnabled 0xa3ec1883 → bool
name 0x06fdde03 → string
offer 0xc028df06 → address
quorum 0x1703a018 → uint256
recoveryDisabled 0xb40e80d1 → bool
symbol 0x95d89b41 → string
terms 0xd5025625 → string
totalSupply 0x18160ddd → uint256
unwrapConversionFactor 0x0832e470 → uint256
votePeriod 0xa7813587 → uint256
wrapped 0x50e70d48 → address
Write Contract 19 functions
These functions modify contract state and require a wallet transaction to execute.
approve 0x095ea7b3
address spender
uint256 value
returns: bool
burn 0x42966c68
uint256 amount
clearClaim 0x6b03ed5f
No parameters
declareLost 0x26773ddd
address collateralType
address lostAddress
decreaseAllowance 0xa457c2d7
address spender
uint256 subtractedValue
returns: bool
deleteClaim 0x32a7ae95
address lostAddress
drag 0xfcb79a7e
address buyer
address currency
increaseAllowance 0x39509351
address spender
uint256 addedValue
returns: bool
makeAcquisitionOffer 0xdcc7d4ad
bytes32 salt
uint256 pricePerShare
address currency
migrate 0x8fd3ab80
No parameters
notifyOfferEnded 0x32bc320b
No parameters
onTokenTransfer 0xa4c0ed36
address from
uint256 amount
bytes
recover 0x0cd865ec
address lostAddress
setRecoverable 0x6427ed97
bool enabled
transfer 0xa9059cbb
address to
uint256 value
returns: bool
transferAndCall 0x4000aea0
address recipient
uint256 amount
bytes data
returns: bool
transferFrom 0x23b872dd
address sender
address recipient
uint256 amount
returns: bool
unwrap 0xde0e9a3e
uint256 amount
wrap 0xbf376c7a
address shareholder
uint256 amount
Recent Transactions
No transactions found for this address