Address Contract Verified
Address
0x143F369d362E6F9Bb2b9282c48e55d19f5EB5305
Balance
0 ETH
Nonce
1
Code Size
15597 bytes
Creator
0x55749224...2409 at tx 0x5113b92a...6abbfc
Indexed Transactions
0
Contract Bytecode
15597 bytes
0x6080604052600436106101755760003560e01c80638456cb59116100cb578063ca61164f1161007f578063e2c0a28111610059578063e2c0a281146103d4578063e45d3d28146103f4578063f2fde38b1461041457600080fd5b8063ca61164f14610374578063d7db6cba14610394578063df3e2da8146103b457600080fd5b80638da5cb5b116100b05780638da5cb5b1461031657806397a6278e14610334578063b6e879c41461035457600080fd5b80638456cb59146102e157806384e79842146102f657600080fd5b80633f4ba83a1161012d5780635c975abb116101075780635c975abb14610294578063715018a6146102ac57806381f6165a146102c157600080fd5b80633f4ba83a146102495780634f1ef2861461025e57806352d1902d1461027157600080fd5b80632c54de4f1161015e5780632c54de4f146101e75780633416794d146102095780633659cfe61461022957600080fd5b80631ffbb0641461017a5780632b0fb787146101af575b600080fd5b34801561018657600080fd5b5061019a610195366004612ad3565b610434565b60405190151581526020015b60405180910390f35b3480156101bb57600080fd5b506101cf6101ca366004612b39565b610447565b6040516001600160a01b0390911681526020016101a6565b3480156101f357600080fd5b50610207610202366004612ba5565b61047e565b005b34801561021557600080fd5b50610207610224366004612bf6565b6105d1565b34801561023557600080fd5b50610207610244366004612ad3565b610702565b34801561025557600080fd5b5061020761087d565b61020761026c366004612d54565b61088f565b34801561027d57600080fd5b506102866109fb565b6040519081526020016101a6565b3480156102a057600080fd5b5060335460ff1661019a565b3480156102b857600080fd5b50610207610ac0565b3480156102cd57600080fd5b506101cf6102dc366004612e32565b610ad2565b3480156102ed57600080fd5b50610207610e82565b34801561030257600080fd5b50610207610311366004612ad3565b610e92565b34801561032257600080fd5b506065546001600160a01b03166101cf565b34801561034057600080fd5b5061020761034f366004612ad3565b610f32565b34801561036057600080fd5b5061020761036f366004612f3d565b610fd2565b34801561038057600080fd5b506101cf61038f366004613182565b611314565b3480156103a057600080fd5b506102076103af366004612bf6565b6116c1565b3480156103c057600080fd5b506101cf6103cf3660046132d7565b61189d565b3480156103e057600080fd5b506102076103ef366004613315565b611d52565b34801561040057600080fd5b5061028661040f366004612b39565b611d64565b34801561042057600080fd5b5061020761042f366004612ad3565b611d9d565b6000610441609783611e2a565b92915050565b6000609e600061045987878787611d64565b81526020810191909152604001600020546001600160a01b031690505b949350505050565b61048733610434565b6104ef5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b60648201526084015b60405180910390fd5b6040517f9fc1d0e70000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152838116602483015260448201839052851690639fc1d0e7906064016020604051808303816000875af115801561055f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105839190613357565b507fbe8d94bc98dc799fb1bc73ba798ff2a489f0c999250f4ff7a64fbe46d97fb7346105ae85611ec8565b858385866040516105c395949392919061339f565b60405180910390a150505050565b6105da33610434565b61063d5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b60648201526084016104e6565b6040517f9dc29fac0000000000000000000000000000000000000000000000000000000081526001600160a01b03838116600483015260248201839052841690639dc29fac90604401600060405180830381600087803b1580156106a057600080fd5b505af11580156106b4573d6000803e3d6000fd5b505050507f318f28bc37d09d28848b584955361b10ff0af378ba45a0f023b0c66c9eaea1526106e284611ec8565b8483856040516106f594939291906133db565b60405180910390a1505050565b6001600160a01b037f000000000000000000000000143f369d362e6f9bb2b9282c48e55d19f5eb530516300361078f5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084016104e6565b7f000000000000000000000000143f369d362e6f9bb2b9282c48e55d19f5eb53056001600160a01b03166107ea7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b0316146108555760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b60648201526084016104e6565b61085e81611f2c565b6040805160008082526020820190925261087a91839190611f34565b50565b6108856120d9565b61088d612133565b565b6001600160a01b037f000000000000000000000000143f369d362e6f9bb2b9282c48e55d19f5eb530516300361091c5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b19195b1959d85d1958d85b1b60a21b60648201526084016104e6565b7f000000000000000000000000143f369d362e6f9bb2b9282c48e55d19f5eb53056001600160a01b03166109777f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b6001600160a01b0316146109e25760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201526b6163746976652070726f787960a01b60648201526084016104e6565b6109eb82611f2c565b6109f782826001611f34565b5050565b6000306001600160a01b037f000000000000000000000000143f369d362e6f9bb2b9282c48e55d19f5eb53051614610a9b5760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016104e6565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b610ac86120d9565b61088d6000612185565b6000610adc6121d7565b8451516003141580610af9575060408501516001600160a01b0316155b15610b3257846040517f14552c240000000000000000000000000000000000000000000000000000000081526004016104e691906134b4565b600085604001516001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b76573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b9e91908101906134c7565b604051602001610bae919061353e565b60408051601f198184030181528282018252600583527f66734345540000000000000000000000000000000000000000000000000000006020840152609b5491517fff679e9d0000000000000000000000000000000000000000000000000000000081529093506000916001600160a01b03169063ff679e9d90610c37906002906004016135a9565b6020604051808303816000875af1158015610c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7a91906135bc565b90506000609c60009054906101000a90046001600160a01b03166001600160a01b03166343bdb458336040518060c00160405280610cb8600261226a565b6001600160a01b039081168252609854811660208301528781166040808401919091526099549091166060830152608082018a905260a0909101889052517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152610d319291908e908e90600401613640565b6020604051808303816000875af1158015610d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d7491906135bc565b6040516340c10f1960e01b81526001600160a01b038881166004830152602482018a9052919250908216906340c10f1990604401600060405180830381600087803b158015610dc257600080fd5b505af1158015610dd6573d6000803e3d6000fd5b50505050806001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610e1557600080fd5b505af1158015610e29573d6000803e3d6000fd5b505050507f273b9f884ffe346b2bb72a39705c98bb4a8d5f9aad5dd026f9fb70724ddc95e3610e5782611ec8565b8286868b8b604051610e6e96959493929190613687565b60405180910390a198975050505050505050565b610e8a6120d9565b61088d6122b3565b610e9a6120d9565b6001600160a01b038116610ef05760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f20616464726573730060448201526064016104e6565b610efb6097826122f0565b6040516001600160a01b038216907ff68e73cec97f2d70aa641fb26e87a4383686e2efacb648f2165aeb02ac562ec590600090a250565b610f3a6120d9565b6001600160a01b038116610f905760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420617267756d656e74202d207a65726f20616464726573730060448201526064016104e6565b610f9b60978261236c565b6040516001600160a01b038216907fed9c8ad8d5a0a66898ea49d2956929c93ae2e8bd50281b2ed897c5d1a6737e0b90600090a250565b600054610100900460ff1615808015610ff25750600054600160ff909116105b8061100c5750303b15801561100c575060005460ff166001145b61107e5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084016104e6565b6000805460ff1916600117905580156110a1576000805461ff0019166101001790555b6001600160a01b0386166110f857604051636cbb462960e01b815260206004820152601060248201527f4964656e7469747952656769737472790000000000000000000000000000000060448201526064016104e6565b6001600160a01b03851661114f57604051636cbb462960e01b815260206004820152600d60248201527f41646d696e4964656e746974790000000000000000000000000000000000000060448201526064016104e6565b6001600160a01b0384166111a657604051636cbb462960e01b815260206004820152601260248201527f5065726d697373696f6e734d616e61676572000000000000000000000000000060448201526064016104e6565b6001600160a01b0383166111fd57604051636cbb462960e01b815260206004820152601160248201527f436f6d706c69616e6365466163746f727900000000000000000000000000000060448201526064016104e6565b6001600160a01b03821661125457604051636cbb462960e01b815260206004820152600d60248201527f546f6b656e73466163746f72790000000000000000000000000000000000000060448201526064016104e6565b61125c61240a565b61126461247d565b61126e88886124f0565b609880546001600160a01b03199081166001600160a01b0389811691909117909255609980548216888416179055609a80548216878416179055609b80548216868416179055609c8054909116918416919091179055801561130a576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b600061131e6121d7565b8460a00151516003141580611336575060e085015151155b80611345575061010085015151155b8061135257506020850151155b8061135f575060c0850151155b1561139857846040517f03c183950000000000000000000000000000000000000000000000000000000081526004016104e691906137af565b60a08401515115806113ad5750604084015151155b806113bb5750606084015151155b806113c557508351155b156113fe57836040517f6fbb6f1c0000000000000000000000000000000000000000000000000000000081526004016104e6919061385d565b609b546040517fff679e9d0000000000000000000000000000000000000000000000000000000081526000916001600160a01b03169063ff679e9d90611449906003906004016135a9565b6020604051808303816000875af1158015611468573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148c91906135bc565b90506000609c60009054906101000a90046001600160a01b03166001600160a01b0316637351a9fd336040518060c001604052806114ca600361226a565b6001600160a01b03908116825260985481166020808401919091528882166040808501919091526099549092166060840152815180820183526000808252608085019190915282519182018352815260a090920191909152517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526115609291908c908c908c90600401613870565b6020604051808303816000875af115801561157f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a391906135bc565b60208601516040516340c10f1960e01b81526001600160a01b03878116600483015260248201929092529192508216906340c10f1990604401600060405180830381600087803b1580156115f657600080fd5b505af115801561160a573d6000803e3d6000fd5b50505050806001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561164957600080fd5b505af115801561165d573d6000803e3d6000fd5b505050507f273b9f884ffe346b2bb72a39705c98bb4a8d5f9aad5dd026f9fb70724ddc95e361168b82611ec8565b828960e001518a61010001518960200151896040516116af96959493929190613687565b60405180910390a19695505050505050565b6116ca33610434565b61172d5760405162461bcd60e51b815260206004820152602e60248201527f4167656e74526f6c653a2063616c6c657220646f6573206e6f7420686176652060448201526d746865204167656e7420726f6c6560901b60648201526084016104e6565b6040516340c10f1960e01b81526001600160a01b038381166004830152602482018390528491908216906340c10f1990604401600060405180830381600087803b15801561177a57600080fd5b505af115801561178e573d6000803e3d6000fd5b505050507f273b9f884ffe346b2bb72a39705c98bb4a8d5f9aad5dd026f9fb70724ddc95e36117bc85611ec8565b85836001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156117fb573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261182391908101906134c7565b846001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611861573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261188991908101906134c7565b86886040516105c396959493929190613687565b60006118a76121d7565b6118b18480613937565b905060031415806118ce57506118ca6020850185613937565b1590505b806118e557506118e16040850185613937565b1590505b1561191e57836040517f9fa61ed70000000000000000000000000000000000000000000000000000000081526004016104e69190613a52565b609a546040516349e40eeb60e11b81526001600160a01b03909116906393c81dd690611951908690600090600401613a65565b602060405180830381865afa15801561196e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119929190613357565b6119ba57604051630201de7d60e11b81526001600160a01b03841660048201526024016104e6565b60006119d66119c98680613937565b61040f6040890189613937565b6000818152609e60205260409020549091506001600160a01b031615611a4357611a008580613937565b611a0d6040880188613937565b6040517f8d47a5750000000000000000000000000000000000000000000000000000000081526004016104e69493929190613a8b565b6000611a4f8680613937565b611a5c6020890189613937565b604051602001611a6f9493929190613abd565b60408051601f1981840301815291905290506000611a8d8780613937565b604051602001611a9e929190613b04565b60408051601f1981840301815290829052609b547fff679e9d0000000000000000000000000000000000000000000000000000000083529092506000916001600160a01b039091169063ff679e9d90611afc906001906004016135a9565b6020604051808303816000875af1158015611b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3f91906135bc565b90506000609c60009054906101000a90046001600160a01b03166001600160a01b0316638d5dc33b336040518060c00160405280611b7d600161226a565b6001600160a01b039081168252609854811660208301528781166040808401919091526099549091166060830152608082018a905260a0909101889052517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152611bf49291908e90600401613b3d565b6020604051808303816000875af1158015611c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c3791906135bc565b6000868152609e60205260409081902080546001600160a01b0319166001600160a01b0384811691821790925591516340c10f1960e01b8152908b166004820152602481018a9052919250906340c10f1990604401600060405180830381600087803b158015611ca657600080fd5b505af1158015611cba573d6000803e3d6000fd5b50505050806001600160a01b0316633f4ba83a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611cf957600080fd5b505af1158015611d0d573d6000803e3d6000fd5b505050507f273b9f884ffe346b2bb72a39705c98bb4a8d5f9aad5dd026f9fb70724ddc95e3611d3b82611ec8565b8286868b8d604051610e6e96959493929190613687565b611d5a6120d9565b6109f782826124f0565b600084848484604051602001611d7d9493929190613b71565b604051602081830303815290604052805190602001209050949350505050565b611da56120d9565b6001600160a01b038116611e215760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016104e6565b61087a81612185565b60006001600160a01b038216611ea85760405162461bcd60e51b815260206004820152602260248201527f526f6c65733a206163636f756e7420697320746865207a65726f20616464726560448201527f737300000000000000000000000000000000000000000000000000000000000060648201526084016104e6565b506001600160a01b03166000908152602091909152604090205460ff1690565b6000816001600160a01b031663f8333bfa6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f08573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104419190613b93565b61087a6120d9565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611f6c57611f67836126b3565b505050565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611fc6575060408051601f3d908101601f19168201909252611fc391810190613bb0565b60015b6120385760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f74205555505300000000000000000000000000000000000060648201526084016104e6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146120cd5760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c6555554944000000000000000000000000000000000000000000000060648201526084016104e6565b50611f67838383612771565b6065546001600160a01b0316331461088d5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016104e6565b61213b61279c565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b609a546040516349e40eeb60e11b81526001600160a01b03909116906393c81dd69061220a903390600090600401613a65565b602060405180830381865afa158015612227573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224b9190613357565b61088d57604051630201de7d60e11b81523360048201526024016104e6565b6000609d600083600381111561228257612282613379565b600381111561229357612293613379565b81526020810191909152604001600020546001600160a01b031692915050565b6122bb6127ee565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586121683390565b6122fa8282611e2a565b156123475760405162461bcd60e51b815260206004820152601f60248201527f526f6c65733a206163636f756e7420616c72656164792068617320726f6c650060448201526064016104e6565b6001600160a01b0316600090815260209190915260409020805460ff19166001179055565b6123768282611e2a565b6123e85760405162461bcd60e51b815260206004820152602160248201527f526f6c65733a206163636f756e7420646f6573206e6f74206861766520726f6c60448201527f650000000000000000000000000000000000000000000000000000000000000060648201526084016104e6565b6001600160a01b0316600090815260209190915260409020805460ff19169055565b600054610100900460ff166124755760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104e6565b61088d612841565b600054610100900460ff166124e85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104e6565b61088d6128b5565b60005b81811015611f67573683838381811061250e5761250e613bc9565b604002919091019150600090506125286020830183612ad3565b6001600160a01b0316148061255d5750600061254a6040830160208401613bdf565b600381111561255b5761255b613379565b145b1561259657806040517f5afd08ad0000000000000000000000000000000000000000000000000000000081526004016104e69190613bfc565b6000609d816125ab6040850160208601613bdf565b60038111156125bc576125bc613379565b60038111156125cd576125cd613379565b81526020810191909152604001600020546001600160a01b03161461262f576125fc6040820160208301613bdf565b6040517f537f5b510000000000000000000000000000000000000000000000000000000081526004016104e691906135a9565b61263c6020820182612ad3565b609d60006126506040850160208601613bdf565b600381111561266157612661613379565b600381111561267257612672613379565b8152602081019190915260400160002080546001600160a01b0319166001600160a01b039290921691909117905550806126ab81613c3a565b9150506124f3565b6001600160a01b0381163b6127305760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e74726163740000000000000000000000000000000000000060648201526084016104e6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b61277a8361292c565b6000825111806127875750805b15611f6757612796838361296c565b50505050565b60335460ff1661088d5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016104e6565b60335460ff161561088d5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016104e6565b600054610100900460ff166128ac5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104e6565b61088d33612185565b600054610100900460ff166129205760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b60648201526084016104e6565b6033805460ff19169055565b612935816126b3565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606129918383604051806060016040528060278152602001613c9160279139612998565b9392505050565b6060600080856001600160a01b0316856040516129b59190613c61565b600060405180830381855af49150503d80600081146129f0576040519150601f19603f3d011682016040523d82523d6000602084013e6129f5565b606091505b5091509150612a0686838387612a10565b9695505050505050565b60608315612a7f578251600003612a78576001600160a01b0385163b612a785760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016104e6565b5081610476565b6104768383815115612a945781518083602001fd5b8060405162461bcd60e51b81526004016104e69190613c7d565b6001600160a01b038116811461087a57600080fd5b8035612ace81612aae565b919050565b600060208284031215612ae557600080fd5b813561299181612aae565b60008083601f840112612b0257600080fd5b50813567ffffffffffffffff811115612b1a57600080fd5b602083019150836020828501011115612b3257600080fd5b9250929050565b60008060008060408587031215612b4f57600080fd5b843567ffffffffffffffff80821115612b6757600080fd5b612b7388838901612af0565b90965094506020870135915080821115612b8c57600080fd5b50612b9987828801612af0565b95989497509550505050565b60008060008060808587031215612bbb57600080fd5b8435612bc681612aae565b93506020850135612bd681612aae565b92506040850135612be681612aae565b9396929550929360600135925050565b600080600060608486031215612c0b57600080fd5b8335612c1681612aae565b92506020840135612c2681612aae565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715612c7057612c70612c37565b60405290565b60405160e0810167ffffffffffffffff81118282101715612c7057612c70612c37565b604051610120810167ffffffffffffffff81118282101715612c7057612c70612c37565b604051601f8201601f1916810167ffffffffffffffff81118282101715612ce657612ce6612c37565b604052919050565b600067ffffffffffffffff821115612d0857612d08612c37565b50601f01601f191660200190565b6000612d29612d2484612cee565b612cbd565b9050828152838383011115612d3d57600080fd5b828260208301376000602084830101529392505050565b60008060408385031215612d6757600080fd5b8235612d7281612aae565b9150602083013567ffffffffffffffff811115612d8e57600080fd5b8301601f81018513612d9f57600080fd5b612dae85823560208401612d16565b9150509250929050565b600082601f830112612dc957600080fd5b61299183833560208501612d16565b6002811061087a57600080fd5b8035612ace81612dd8565b600060208284031215612e0257600080fd5b6040516020810181811067ffffffffffffffff82111715612e2557612e25612c37565b6040529135825250919050565b60008060008060808587031215612e4857600080fd5b843567ffffffffffffffff80821115612e6057600080fd5b9086019060608289031215612e7457600080fd5b612e7c612c4d565b823582811115612e8b57600080fd5b612e978a828601612db8565b82525060208301359150612eaa82612dd8565b81602082015260408301359250612ec083612aae565b6040810192909252509350612ed88660208701612df0565b925060408501359150612eed60608601612ac3565b905092959194509250565b60008083601f840112612f0a57600080fd5b50813567ffffffffffffffff811115612f2257600080fd5b6020830191508360208260061b8501011115612b3257600080fd5b600080600080600080600060c0888a031215612f5857600080fd5b873567ffffffffffffffff811115612f6f57600080fd5b612f7b8a828b01612ef8565b9098509650506020880135612f8f81612aae565b94506040880135612f9f81612aae565b93506060880135612faf81612aae565b92506080880135612fbf81612aae565b915060a0880135612fcf81612aae565b8091505092959891949750929550565b803560078110612ace57600080fd5b6004811061087a57600080fd5b8035612ace81612fee565b600060e0828403121561301857600080fd5b613020612c76565b90508135815261303260208301612ffb565b6020820152604082013567ffffffffffffffff8082111561305257600080fd5b61305e85838601612db8565b6040840152606084013591508082111561307757600080fd5b61308385838601612db8565b6060840152608084013591508082111561309c57600080fd5b6130a885838601612db8565b608084015260a08401359150808211156130c157600080fd5b6130cd85838601612db8565b60a084015260c08401359150808211156130e657600080fd5b506130f384828501612db8565b60c08301525092915050565b600060e0828403121561311157600080fd5b613119612c76565b9050813581526020820135602082015260408201356005811061313b57600080fd5b6040820152606082810135908201526080820135600b811061315c57600080fd5b608082015260a0828101359082015261317760c08301612ac3565b60c082015292915050565b600080600080610140858703121561319957600080fd5b843567ffffffffffffffff808211156131b157600080fd5b818701915061012080838a0312156131c857600080fd5b6131d0612c99565b83358152602084013560208201526131ea60408501612de5565b60408201526131fb60608501612fdf565b606082015261320c60808501612de5565b608082015260a08401358381111561322357600080fd5b61322f8b828701612db8565b60a08301525060c084013560c082015260e08401358381111561325157600080fd5b61325d8b828701612db8565b60e083015250610100808501358481111561327757600080fd5b6132838c828801612db8565b8284015250508097505060208801359250818311156132a157600080fd5b6132ad89848a01613006565b95506132bc8960408a016130ff565b94506132c9818901612ac3565b935050505092959194509250565b6000806000606084860312156132ec57600080fd5b833567ffffffffffffffff81111561330357600080fd5b840160608187031215612c1657600080fd5b6000806020838503121561332857600080fd5b823567ffffffffffffffff81111561333f57600080fd5b61334b85828601612ef8565b90969095509350505050565b60006020828403121561336957600080fd5b8151801515811461299157600080fd5b634e487b7160e01b600052602160045260246000fd5b6004811061087a5761087a613379565b60a081016133ac8761338f565b9581526001600160a01b0394851660208201526040810193909352908316606083015290911660809091015290565b608081016133e88661338f565b9481526001600160a01b039384166020820152604081019290925290911660609091015290565b60005b8381101561342a578181015183820152602001613412565b50506000910152565b6000815180845261344b81602086016020860161340f565b601f01601f19169290920160200192915050565b6002811061087a5761087a613379565b60008151606084526134846060850182613433565b905060208301516134948161345f565b60208501526040928301516001600160a01b031692909301919091525090565b602081526000612991602083018461346f565b6000602082840312156134d957600080fd5b815167ffffffffffffffff8111156134f057600080fd5b8201601f8101841361350157600080fd5b805161350f612d2482612cee565b81815285602083850101111561352457600080fd5b61353582602083016020860161340f565b95945050505050565b7f4672696374696f6e6c657373202d204469676974616c2053656375726974792081527f6f6620000000000000000000000000000000000000000000000000000000000060208201526000825161359c81602385016020870161340f565b9190910160230192915050565b602081016135b68361338f565b91905290565b6000602082840312156135ce57600080fd5b815161299181612aae565b60006001600160a01b0380835116845280602084015116602085015280604084015116604085015280606084015116606085015250608082015160c0608085015261362760c0850182613433565b905060a083015184820360a08601526135358282613433565b6001600160a01b038516815260806020820152600061366260808301866135d9565b8281036040840152613674818661346f565b9150508251606083015295945050505050565b6136908761338f565b86815260006001600160a01b03808816602084015260c060408401526136b960c0840188613433565b83810360608501526136cb8188613433565b6080850196909652509290921660a09091015250949350505050565b6136f08161345f565b9052565b6007811061087a5761087a613379565b6136f0816136f4565b60006101208251845260208301516020850152604083015161373260408601826136e7565b5060608301516137456060860182613704565b50608083015161375860808601826136e7565b5060a08301518160a086015261377082860182613433565b91505060c083015160c085015260e083015184820360e08601526137948282613433565b9150506101008084015185830382870152612a068382613433565b602081526000612991602083018461370d565b80518252600060208201516137d68161338f565b80602085015250604082015160e060408501526137f660e0850182613433565b90506060830151848203606086015261380f8282613433565b915050608083015184820360808601526138298282613433565b91505060a083015184820360a08601526138438282613433565b91505060c083015184820360c08601526135358282613433565b60208152600061299160208301846137c2565b60006101606001600160a01b0388168352806020840152613893818401886135d9565b905082810360408401526138a7818761370d565b905082810360608401526138bb81866137c2565b91505082516080830152602083015160a08301526040830151600581106138e4576138e4613379565b60c0830152606083015160e08301526080830151600b811061390857613908613379565b61010083015260a083015161012083015260c0909201516001600160a01b031661014090910152949350505050565b6000808335601e1984360301811261394e57600080fd5b83018035915067ffffffffffffffff82111561396957600080fd5b602001915036819003821315612b3257600080fd5b6000808335601e1984360301811261399557600080fd5b830160208101925035905067ffffffffffffffff8111156139b557600080fd5b803603821315612b3257600080fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60006139f9828361397e565b60608552613a0b6060860182846139c4565b915050613a1b602084018461397e565b8583036020870152613a2e8382846139c4565b92505050613a3f604084018461397e565b8583036040870152612a068382846139c4565b60208152600061299160208301846139ed565b6001600160a01b038316815260408101613a7e836136f4565b8260208301529392505050565b604081526000613a9f6040830186886139c4565b8281036020840152613ab28185876139c4565b979650505050505050565b8385823760008482017f204672696374696f6e6c6573732000000000000000000000000000000000000081528385600e83013760009301600e019283525090949350505050565b7f667300000000000000000000000000000000000000000000000000000000000081528183600283013760009101600201908152919050565b6001600160a01b0384168152606060208201526000613b5f60608301856135d9565b8281036040840152612a0681856139ed565b8385823760008482016000815283858237600093019283525090949350505050565b600060208284031215613ba557600080fd5b815161299181612fee565b600060208284031215613bc257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215613bf157600080fd5b813561299181612fee565b604081018235613c0b81612aae565b6001600160a01b031682526020830135613c2481612fee565b613c2d8161338f565b8060208401525092915050565b600060018201613c5a57634e487b7160e01b600052601160045260246000fd5b5060010190565b60008251613c7381846020870161340f565b9190910192915050565b602081526000612991602083018461343356fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a2646970667358221220c9d472b724465f6b973dbfadcf82345d6cd0571d8cfaf0d49d058e7ffd54b60a64736f6c63430008110033
Verified Source Code Full Match
Compiler: v0.8.17+commit.8df45f5f
EVM: london
Optimization: Yes (1000 runs)
Roles.sol 99 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
/**
* @title Roles
* @dev Library for managing addresses assigned to a Role.
*/
library Roles {
struct Role {
mapping(address => bool) bearer;
}
/**
* @dev Give an account access to this role.
*/
function add(Role storage role, address account) internal {
require(!has(role, account), "Roles: account already has role");
role.bearer[account] = true;
}
/**
* @dev Remove an account's access to this role.
*/
function remove(Role storage role, address account) internal {
require(has(role, account), "Roles: account does not have role");
role.bearer[account] = false;
}
/**
* @dev Check if an account has this role.
* @return bool
*/
function has(Role storage role, address account) internal view returns (bool) {
require(account != address(0), "Roles: account is the zero address");
return role.bearer[account];
}
}
FrictionlessTreasuryManager.sol 417 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { IIdentityRegistry } from "@ERC-3643/registry/interface/IIdentityRegistry.sol";
import { AgentRoleUpgradeable } from "@ERC-3643/roles/AgentRoleUpgradeable.sol";
import { UUPSUpgradeable } from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { IToken } from "@ERC-3643/token/IToken.sol";
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
import { IFrictionlessDigitalSecurityToken } from "@interface/IFrictionlessDigitalSecurityToken.sol";
import { IFrictionlessFundDepositToken } from "@interface/IFrictionlessFundDepositToken.sol";
import { IFrictionlessOnChainAssetToken } from "@interface/IFrictionlessOnChainAssetToken.sol";
import { IFrictionlessComplianceFactory } from "@interface/IFrictionlessComplianceFactory.sol";
import { IFrictionlessTokensFactory } from "@interface/IFrictionlessTokensFactory.sol";
import { IFrictionlessPermissionsManager } from "@interface/IFrictionlessPermissionsManager.sol";
import { IFrictionlessTreasuryManager } from "@interface/IFrictionlessTreasuryManager.sol";
import { IFrictionlessAttestationManager } from "@interface/IFrictionlessAttestationManager.sol";
/**
* @title FrictionlessTreasuryManager - Manages the minting, transfer and burning of all tokens in the Frictionless protocol
* @author Frictionless Group Holdings S.à.r.l
* @notice See {IFrictionlessTreasuryManager}
*/
contract FrictionlessTreasuryManager is
IFrictionlessTreasuryManager,
PausableUpgradeable,
OwnableUpgradeable,
AgentRoleUpgradeable,
UUPSUpgradeable
{
/// @dev The OnChain Identity registry
address private _identityRegistry;
/// @dev The OnChain Identity for the PROTOCOL_ADMIN
address private _adminIdentity;
/// @dev The Frictionless Permissions Manager
address private _permissionsManager;
/// @dev The compliance factory to load the compliance contract for each specific token
IFrictionlessComplianceFactory private _complianceFactory;
/// @dev The tokens factory to verify the type of token
IFrictionlessTokensFactory private _tokensFactory;
/// @dev The map associating the Frictionless token type with the relevant Implementation Authority contract
mapping(IBasicFrictionlessToken.FrictionlessTokenTypes => address) internal _tokensImplAuthority;
mapping(bytes32 => address) internal _existingFundDepositTokens;
/// @dev Modifier to ensure functions are callable by the Treasury role only.
modifier onlyTreasury() {
_onlyTreasury();
_;
}
/**
* @dev initialize the FrictionlessTreasuryManager
* @param identityRegistry_ the address of the deployed TREX Identity Registry
* @param adminIdentity_ the address of the deployed PROTOCOL_ADMIN OnChainId
* @param permissionsManager_ the address of the deployed FrictionlessPermissionsManager
* requires identityRegistry_ to be valid contract address
* requires adminIdentity_ to be valid contract address
* requires permissionsManager_ to be valid contract address
*/
function init(
FrictionlessTokenInitData[] calldata initDataArr_,
address identityRegistry_,
address adminIdentity_,
address permissionsManager_,
address complianceFactory_,
address tokensFactory_
) external initializer {
if (identityRegistry_ == address(0)) revert FrictionlessIsZeroAddress("IdentityRegistry");
if (adminIdentity_ == address(0)) revert FrictionlessIsZeroAddress("AdminIdentity");
if (permissionsManager_ == address(0)) revert FrictionlessIsZeroAddress("PermissionsManager");
if (complianceFactory_ == address(0)) revert FrictionlessIsZeroAddress("ComplianceFactory");
if (tokensFactory_ == address(0)) revert FrictionlessIsZeroAddress("TokensFactory");
__Ownable_init();
__Pausable_init();
_setTokensInitData(initDataArr_);
_identityRegistry = identityRegistry_;
_adminIdentity = adminIdentity_;
_permissionsManager = permissionsManager_;
_complianceFactory = IFrictionlessComplianceFactory(complianceFactory_);
_tokensFactory = IFrictionlessTokensFactory(tokensFactory_);
}
/**
* @dev See {PausableUpgradeable-_pause}
*/
function pause() external override onlyOwner {
_pause();
}
/**
* @dev See {PausableUpgradeable-_unpause}
*/
function unpause() external override onlyOwner {
_unpause();
}
/// @inheritdoc IFrictionlessTreasuryManager
function setTokensInitData(FrictionlessTokenInitData[] calldata initDataArr_) external onlyOwner {
_setTokensInitData(initDataArr_);
}
/// @inheritdoc IFrictionlessTreasuryManager
function mintFundDepositForTreasury(
IFrictionlessFundDepositToken.FFDImmutableData calldata depositData_,
address treasuryAddress_,
uint256 amount_
) public override onlyTreasury returns (address) {
if (
bytes(depositData_.currency).length != 3 ||
bytes(depositData_.description).length == 0 ||
bytes(depositData_.fundIBAN).length == 0
) {
revert FrictionlessTreasuryManagerInvalidDepositData(depositData_);
}
if (
!IFrictionlessPermissionsManager(_permissionsManager).hasClaim(
treasuryAddress_,
IFrictionlessPermissionsManager.FrictionlessPermissionedUser.PROTOCOL_TREASURY
)
) {
revert FrictionlessTreasuryManagerNotAProtocolTreasury(treasuryAddress_);
}
bytes32 tokenKey_ = getFundDepositTokenKey(depositData_.currency, depositData_.fundIBAN);
if (_existingFundDepositTokens[tokenKey_] != address(0)) {
revert FrictionlessTreasuryManagerFundDepositTokenAlreadyExists(
depositData_.currency,
depositData_.fundIBAN
);
}
string memory tokenName_ = string(
abi.encodePacked(depositData_.currency, " Frictionless ", depositData_.description)
);
string memory tokenSymbol_ = string(abi.encodePacked("fs", depositData_.currency));
address compliance_ = _complianceFactory.deployCompliance(
IBasicFrictionlessToken.FrictionlessTokenTypes.FUND_DEPOSIT_TOKEN
);
address tokenProxyAddr_ = _tokensFactory.deployFundDepositToken(
msg.sender,
IFrictionlessTokensFactory.BaseTokenInitParams(
_getTokenImplAuthority(IBasicFrictionlessToken.FrictionlessTokenTypes.FUND_DEPOSIT_TOKEN),
_identityRegistry,
compliance_,
_adminIdentity,
tokenName_,
tokenSymbol_
),
depositData_
);
_existingFundDepositTokens[tokenKey_] = tokenProxyAddr_;
// Mint the deposit tokens to the Treasury address
IToken(tokenProxyAddr_).mint(treasuryAddress_, amount_);
IToken(tokenProxyAddr_).unpause();
emit FrictionlessTokenMinted(
_getTokenType(tokenProxyAddr_),
tokenProxyAddr_,
tokenName_,
tokenSymbol_,
amount_,
treasuryAddress_
);
return tokenProxyAddr_;
}
/// @inheritdoc IFrictionlessTreasuryManager
function mintDigitalSecurity(
IFrictionlessDigitalSecurityToken.FDSImmutableData memory initData_,
IFrictionlessDigitalSecurityToken.FDSMutableData memory updateData_,
uint256 amount_,
address userAddress_
) public override onlyTreasury returns (address) {
if (bytes(initData_.baseCurrency).length != 3 || initData_.onChainAssetAddress == address(0)) {
revert FrictionlessTreasuryManagerInvalidFDSImmutableData(initData_);
}
string memory tokenName_ = string(
abi.encodePacked("Frictionless - Digital Security of ", IToken(initData_.onChainAssetAddress).symbol())
);
string memory tokenSymbol_ = "fsCET";
address compliance_ = _complianceFactory.deployCompliance(
IBasicFrictionlessToken.FrictionlessTokenTypes.DIGITAL_SECURITY_TOKEN
);
address tokenProxyAddr_ = _tokensFactory.deployDigitalSecurityToken(
msg.sender,
IFrictionlessTokensFactory.BaseTokenInitParams(
_getTokenImplAuthority(IBasicFrictionlessToken.FrictionlessTokenTypes.DIGITAL_SECURITY_TOKEN),
_identityRegistry,
compliance_,
_adminIdentity,
tokenName_,
tokenSymbol_
),
initData_,
updateData_
);
// Mint the Digital Security to the relevant registered Investor
IToken(tokenProxyAddr_).mint(userAddress_, amount_);
IToken(tokenProxyAddr_).unpause();
emit FrictionlessTokenMinted(
_getTokenType(tokenProxyAddr_),
tokenProxyAddr_,
tokenName_,
tokenSymbol_,
amount_,
userAddress_
);
return tokenProxyAddr_;
}
/// @inheritdoc IFrictionlessTreasuryManager
function mintOnChainAsset(
IFrictionlessOnChainAssetToken.FOCASpecData memory specData_,
IFrictionlessOnChainAssetToken.FOCAIssuanceData memory issuanceData_,
IFrictionlessOnChainAssetToken.FOCAUpdateData memory updateData_,
address custodianAddress_
) public override onlyTreasury returns (address) {
if (
bytes(specData_.baseCurrency).length != 3 ||
bytes(specData_.name).length == 0 ||
bytes(specData_.symbol).length == 0 ||
specData_.maturityDays == 0 ||
specData_.stripTotal == 0
) {
revert FrictionlessTreasuryManagerInvalidFOCASpecData(specData_);
}
if (
bytes(issuanceData_.issuanceDocs).length == 0 ||
bytes(issuanceData_.onChainAssetUUID).length == 0 ||
bytes(issuanceData_.issuerUUID).length == 0 ||
issuanceData_.auctionedOn == 0
) {
revert FrictionlessTreasuryManagerInvalidFOCAIssuanceData(issuanceData_);
}
address compliance_ = _complianceFactory.deployCompliance(
IBasicFrictionlessToken.FrictionlessTokenTypes.ON_CHAIN_ASSET_TOKEN
);
address tokenProxyAddr_ = _tokensFactory.deployOnChainAssetToken(
msg.sender,
IFrictionlessTokensFactory.BaseTokenInitParams(
_getTokenImplAuthority(IBasicFrictionlessToken.FrictionlessTokenTypes.ON_CHAIN_ASSET_TOKEN),
_identityRegistry,
compliance_,
_adminIdentity,
"",
""
),
specData_,
issuanceData_,
updateData_
);
// Mint the OnChain Asset to the relevant registered PERMISSIONED_CUSTODIAN
IToken(tokenProxyAddr_).mint(custodianAddress_, updateData_.total);
IToken(tokenProxyAddr_).unpause();
emit FrictionlessTokenMinted(
_getTokenType(tokenProxyAddr_),
tokenProxyAddr_,
specData_.name,
specData_.symbol,
updateData_.total,
custodianAddress_
);
return tokenProxyAddr_;
}
/// @inheritdoc IFrictionlessTreasuryManager
function mintTokenForUser(address tokenAddr_, address userAddress_, uint256 amount_) public override onlyAgent {
IToken token_ = IToken(tokenAddr_);
token_.mint(userAddress_, amount_);
emit FrictionlessTokenMinted(
_getTokenType(tokenAddr_),
tokenAddr_,
token_.name(),
token_.symbol(),
amount_,
userAddress_
);
}
/// @inheritdoc IFrictionlessTreasuryManager
function transferToken(
address tokenAddr_,
address userAddressFrom_,
address userAddressTo_,
uint256 amount_
) public override onlyAgent {
IToken(tokenAddr_).forcedTransfer(userAddressFrom_, userAddressTo_, amount_);
emit FrictionlessTokenTransferred(
_getTokenType(tokenAddr_),
tokenAddr_,
amount_,
userAddressTo_,
userAddressTo_
);
}
/// @inheritdoc IFrictionlessTreasuryManager
function burnToken(address tokenAddr_, address userAddress_, uint256 amount_) public override onlyAgent {
IToken(tokenAddr_).burn(userAddress_, amount_);
emit FrictionlessTokenBurned(_getTokenType(tokenAddr_), tokenAddr_, amount_, userAddress_);
}
/// @inheritdoc IFrictionlessTreasuryManager
function getFundDepositToken(
string calldata currency_,
string calldata fundIBAN_
) public view override returns (address) {
return _existingFundDepositTokens[getFundDepositTokenKey(currency_, fundIBAN_)];
}
/// @inheritdoc IFrictionlessTreasuryManager
function getFundDepositTokenKey(
string calldata currency_,
string calldata fundIBAN_
) public pure override returns (bytes32) {
return keccak256(abi.encodePacked(currency_, fundIBAN_));
}
/// @dev Returns the address of the implementation authority for the specified Frictionless tokenType_
function _getTokenImplAuthority(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_
) internal view returns (address) {
return _tokensImplAuthority[tokenType_];
}
/// @dev Sets relevant token implementation authority with each associated token type
function _setTokensInitData(FrictionlessTokenInitData[] calldata initDataArr_) internal {
for (uint256 i = 0; i < initDataArr_.length; i++) {
FrictionlessTokenInitData calldata initData_ = initDataArr_[i];
if (
initData_.implAuthority == address(0) ||
initData_.tokenType == IBasicFrictionlessToken.FrictionlessTokenTypes.NONE
) {
revert FrictionlessTreasuryManagerInvalidTokenInitData(initData_);
}
if (_tokensImplAuthority[initData_.tokenType] != address(0)) {
revert FrictionlessTreasuryManagerUnableToUpdateTokenInitData(initData_.tokenType);
}
_tokensImplAuthority[initData_.tokenType] = initData_.implAuthority;
}
}
/// @dev Get the token type as defined by the `IBasicFrictionlessToken.FrictionlessTokenTypes` for a specified deployed token contract address
function _getTokenType(address tokenAddr_) internal view returns (IBasicFrictionlessToken.FrictionlessTokenTypes) {
return IBasicFrictionlessToken(tokenAddr_).getFrictionlessTokenType();
}
// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address) internal virtual override onlyOwner {}
/// @dev throws `FrictionlessTreasuryManagerNotAProtocolTreasury` if the msg.sender is not a PROTOCOL_TREASURY user as per the `FrictionlessPermissionsManager`
function _onlyTreasury() internal view {
if (
!IFrictionlessPermissionsManager(_permissionsManager).hasClaim(
msg.sender,
IFrictionlessPermissionsManager.FrictionlessPermissionedUser.PROTOCOL_TREASURY
)
) {
revert FrictionlessTreasuryManagerNotAProtocolTreasury(msg.sender);
}
}
}
IIdentityRegistry.sol 255 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "./ITrustedIssuersRegistry.sol";
import "./IClaimTopicsRegistry.sol";
import "./IIdentityRegistryStorage.sol";
import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol";
import "@onchain-id/solidity/contracts/interface/IIdentity.sol";
interface IIdentityRegistry {
/**
* this event is emitted when the ClaimTopicsRegistry has been set for the IdentityRegistry
* the event is emitted by the IdentityRegistry constructor
* `claimTopicsRegistry` is the address of the Claim Topics Registry contract
*/
event ClaimTopicsRegistrySet(address indexed claimTopicsRegistry);
/**
* this event is emitted when the IdentityRegistryStorage has been set for the IdentityRegistry
* the event is emitted by the IdentityRegistry constructor
* `identityStorage` is the address of the Identity Registry Storage contract
*/
event IdentityStorageSet(address indexed identityStorage);
/**
* this event is emitted when the TrustedIssuersRegistry has been set for the IdentityRegistry
* the event is emitted by the IdentityRegistry constructor
* `trustedIssuersRegistry` is the address of the Trusted Issuers Registry contract
*/
event TrustedIssuersRegistrySet(address indexed trustedIssuersRegistry);
/**
* this event is emitted when an Identity is registered into the Identity Registry.
* the event is emitted by the 'registerIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityRegistered(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity is removed from the Identity Registry.
* the event is emitted by the 'deleteIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityRemoved(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity has been updated
* the event is emitted by the 'updateIdentity' function
* `oldIdentity` is the old Identity contract's address to update
* `newIdentity` is the new Identity contract's
*/
event IdentityUpdated(IIdentity indexed oldIdentity, IIdentity indexed newIdentity);
/**
* this event is emitted when an Identity's country has been updated
* the event is emitted by the 'updateCountry' function
* `investorAddress` is the address on which the country has been updated
* `country` is the numeric code (ISO 3166-1) of the new country
*/
event CountryUpdated(address indexed investorAddress, uint16 indexed country);
/**
* @dev Register an identity contract corresponding to a user address.
* Requires that the user doesn't have an identity contract already registered.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's identity contract
* @param _country The country of the investor
* emits `IdentityRegistered` event
*/
function registerIdentity(
address _userAddress,
IIdentity _identity,
uint16 _country
) external;
/**
* @dev Removes an user from the identity registry.
* Requires that the user have an identity contract already deployed that will be deleted.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user to be removed
* emits `IdentityRemoved` event
*/
function deleteIdentity(address _userAddress) external;
/**
* @dev Replace the actual identityRegistryStorage contract with a new one.
* This function can only be called by the wallet set as owner of the smart contract
* @param _identityRegistryStorage The address of the new Identity Registry Storage
* emits `IdentityStorageSet` event
*/
function setIdentityRegistryStorage(address _identityRegistryStorage) external;
/**
* @dev Replace the actual claimTopicsRegistry contract with a new one.
* This function can only be called by the wallet set as owner of the smart contract
* @param _claimTopicsRegistry The address of the new claim Topics Registry
* emits `ClaimTopicsRegistrySet` event
*/
function setClaimTopicsRegistry(address _claimTopicsRegistry) external;
/**
* @dev Replace the actual trustedIssuersRegistry contract with a new one.
* This function can only be called by the wallet set as owner of the smart contract
* @param _trustedIssuersRegistry The address of the new Trusted Issuers Registry
* emits `TrustedIssuersRegistrySet` event
*/
function setTrustedIssuersRegistry(address _trustedIssuersRegistry) external;
/**
* @dev Updates the country corresponding to a user address.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user
* @param _country The new country of the user
* emits `CountryUpdated` event
*/
function updateCountry(address _userAddress, uint16 _country) external;
/**
* @dev Updates an identity contract corresponding to a user address.
* Requires that the user address should be the owner of the identity contract.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by a wallet set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's new identity contract
* emits `IdentityUpdated` event
*/
function updateIdentity(address _userAddress, IIdentity _identity) external;
/**
* @dev function allowing to register identities in batch
* This function can only be called by a wallet set as agent of the smart contract
* Requires that none of the users has an identity contract already registered.
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses of the users
* @param _identities The addresses of the corresponding identity contracts
* @param _countries The countries of the corresponding investors
* emits _userAddresses.length `IdentityRegistered` events
*/
function batchRegisterIdentity(
address[] calldata _userAddresses,
IIdentity[] calldata _identities,
uint16[] calldata _countries
) external;
/**
* @dev This functions checks whether a wallet has its Identity registered or not
* in the Identity Registry.
* @param _userAddress The address of the user to be checked.
* @return 'True' if the address is contained in the Identity Registry, 'false' if not.
*/
function contains(address _userAddress) external view returns (bool);
/**
* @dev This functions checks whether an identity contract
* corresponding to the provided user address has the required claims or not based
* on the data fetched from trusted issuers registry and from the claim topics registry
* @param _userAddress The address of the user to be verified.
* @return 'True' if the address is verified, 'false' if not.
*/
function isVerified(address _userAddress) external view returns (bool);
/**
* @dev Returns the onchainID of an investor.
* @param _userAddress The wallet of the investor
*/
function identity(address _userAddress) external view returns (IIdentity);
/**
* @dev Returns the country code of an investor.
* @param _userAddress The wallet of the investor
*/
function investorCountry(address _userAddress) external view returns (uint16);
/**
* @dev Returns the IdentityRegistryStorage linked to the current IdentityRegistry.
*/
function identityStorage() external view returns (IIdentityRegistryStorage);
/**
* @dev Returns the TrustedIssuersRegistry linked to the current IdentityRegistry.
*/
function issuersRegistry() external view returns (ITrustedIssuersRegistry);
/**
* @dev Returns the ClaimTopicsRegistry linked to the current IdentityRegistry.
*/
function topicsRegistry() external view returns (IClaimTopicsRegistry);
}
AgentRoleUpgradeable.sol 98 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "./Roles.sol";
contract AgentRoleUpgradeable is OwnableUpgradeable {
using Roles for Roles.Role;
Roles.Role private _agents;
event AgentAdded(address indexed _agent);
event AgentRemoved(address indexed _agent);
modifier onlyAgent() {
require(isAgent(msg.sender), "AgentRole: caller does not have the Agent role");
_;
}
function addAgent(address _agent) public onlyOwner {
require(_agent != address(0), "invalid argument - zero address");
_agents.add(_agent);
emit AgentAdded(_agent);
}
function removeAgent(address _agent) public onlyOwner {
require(_agent != address(0), "invalid argument - zero address");
_agents.remove(_agent);
emit AgentRemoved(_agent);
}
function isAgent(address _agent) public view returns (bool) {
return _agents.has(_agent);
}
}
UUPSUpgradeable.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822.sol";
import "../ERC1967/ERC1967Upgrade.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeTo(address newImplementation) external virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
}
OwnableUpgradeable.sol 95 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
PausableUpgradeable.sol 117 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
IToken.sol 460 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "../registry/interface/IIdentityRegistry.sol";
import "../compliance/modular/IModularCompliance.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
/// @dev interface
interface IToken is IERC20 {
/// events
/**
* this event is emitted when the token information is updated.
* the event is emitted by the token init function and by the setTokenInformation function
* `_newName` is the name of the token
* `_newSymbol` is the symbol of the token
* `_newDecimals` is the decimals of the token
* `_newVersion` is the version of the token, current version is 3.0
* `_newOnchainID` is the address of the onchainID of the token
*/
event UpdatedTokenInformation(string indexed _newName, string indexed _newSymbol, uint8 _newDecimals, string
_newVersion, address indexed _newOnchainID);
/**
* this event is emitted when the IdentityRegistry has been set for the token
* the event is emitted by the token constructor and by the setIdentityRegistry function
* `_identityRegistry` is the address of the Identity Registry of the token
*/
event IdentityRegistryAdded(address indexed _identityRegistry);
/**
* this event is emitted when the Compliance has been set for the token
* the event is emitted by the token constructor and by the setCompliance function
* `_compliance` is the address of the Compliance contract of the token
*/
event ComplianceAdded(address indexed _compliance);
/**
* this event is emitted when an investor successfully recovers his tokens
* the event is emitted by the recoveryAddress function
* `_lostWallet` is the address of the wallet that the investor lost access to
* `_newWallet` is the address of the wallet that the investor provided for the recovery
* `_investorOnchainID` is the address of the onchainID of the investor who asked for a recovery
*/
event RecoverySuccess(address indexed _lostWallet, address indexed _newWallet, address indexed _investorOnchainID);
/**
* this event is emitted when the wallet of an investor is frozen or unfrozen
* the event is emitted by setAddressFrozen and batchSetAddressFrozen functions
* `_userAddress` is the wallet of the investor that is concerned by the freezing status
* `_isFrozen` is the freezing status of the wallet
* if `_isFrozen` equals `true` the wallet is frozen after emission of the event
* if `_isFrozen` equals `false` the wallet is unfrozen after emission of the event
* `_owner` is the address of the agent who called the function to freeze the wallet
*/
event AddressFrozen(address indexed _userAddress, bool indexed _isFrozen, address indexed _owner);
/**
* this event is emitted when a certain amount of tokens is frozen on a wallet
* the event is emitted by freezePartialTokens and batchFreezePartialTokens functions
* `_userAddress` is the wallet of the investor that is concerned by the freezing status
* `_amount` is the amount of tokens that are frozen
*/
event TokensFrozen(address indexed _userAddress, uint256 _amount);
/**
* this event is emitted when a certain amount of tokens is unfrozen on a wallet
* the event is emitted by unfreezePartialTokens and batchUnfreezePartialTokens functions
* `_userAddress` is the wallet of the investor that is concerned by the freezing status
* `_amount` is the amount of tokens that are unfrozen
*/
event TokensUnfrozen(address indexed _userAddress, uint256 _amount);
/**
* this event is emitted when the token is paused
* the event is emitted by the pause function
* `_userAddress` is the address of the wallet that called the pause function
*/
event Paused(address _userAddress);
/**
* this event is emitted when the token is unpaused
* the event is emitted by the unpause function
* `_userAddress` is the address of the wallet that called the unpause function
*/
event Unpaused(address _userAddress);
/// functions
/**
* @dev sets the token name
* @param _name the name of token to set
* Only the owner of the token smart contract can call this function
* emits a `UpdatedTokenInformation` event
*/
function setName(string calldata _name) external;
/**
* @dev sets the token symbol
* @param _symbol the token symbol to set
* Only the owner of the token smart contract can call this function
* emits a `UpdatedTokenInformation` event
*/
function setSymbol(string calldata _symbol) external;
/**
* @dev sets the onchain ID of the token
* @param _onchainID the address of the onchain ID to set
* Only the owner of the token smart contract can call this function
* emits a `UpdatedTokenInformation` event
*/
function setOnchainID(address _onchainID) external;
/**
* @dev pauses the token contract, when contract is paused investors cannot transfer tokens anymore
* This function can only be called by a wallet set as agent of the token
* emits a `Paused` event
*/
function pause() external;
/**
* @dev unpauses the token contract, when contract is unpaused investors can transfer tokens
* if their wallet is not blocked & if the amount to transfer is <= to the amount of free tokens
* This function can only be called by a wallet set as agent of the token
* emits an `Unpaused` event
*/
function unpause() external;
/**
* @dev sets an address frozen status for this token.
* @param _userAddress The address for which to update frozen status
* @param _freeze Frozen status of the address
* This function can only be called by a wallet set as agent of the token
* emits an `AddressFrozen` event
*/
function setAddressFrozen(address _userAddress, bool _freeze) external;
/**
* @dev freezes token amount specified for given address.
* @param _userAddress The address for which to update frozen tokens
* @param _amount Amount of Tokens to be frozen
* This function can only be called by a wallet set as agent of the token
* emits a `TokensFrozen` event
*/
function freezePartialTokens(address _userAddress, uint256 _amount) external;
/**
* @dev unfreezes token amount specified for given address
* @param _userAddress The address for which to update frozen tokens
* @param _amount Amount of Tokens to be unfrozen
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event
*/
function unfreezePartialTokens(address _userAddress, uint256 _amount) external;
/**
* @dev sets the Identity Registry for the token
* @param _identityRegistry the address of the Identity Registry to set
* Only the owner of the token smart contract can call this function
* emits an `IdentityRegistryAdded` event
*/
function setIdentityRegistry(address _identityRegistry) external;
/**
* @dev sets the compliance contract of the token
* @param _compliance the address of the compliance contract to set
* Only the owner of the token smart contract can call this function
* calls bindToken on the compliance contract
* emits a `ComplianceAdded` event
*/
function setCompliance(address _compliance) external;
/**
* @dev force a transfer of tokens between 2 whitelisted wallets
* In case the `from` address has not enough free tokens (unfrozen tokens)
* but has a total balance higher or equal to the `amount`
* the amount of frozen tokens is reduced in order to have enough free tokens
* to proceed the transfer, in such a case, the remaining balance on the `from`
* account is 100% composed of frozen tokens post-transfer.
* Require that the `to` address is a verified address,
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The number of tokens to transfer
* @return `true` if successful and revert if unsuccessful
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event if `_amount` is higher than the free balance of `_from`
* emits a `Transfer` event
*/
function forcedTransfer(
address _from,
address _to,
uint256 _amount
) external returns (bool);
/**
* @dev mint tokens on a wallet
* Improved version of default mint method. Tokens can be minted
* to an address if only it is a verified address as per the security token.
* @param _to Address to mint the tokens to.
* @param _amount Amount of tokens to mint.
* This function can only be called by a wallet set as agent of the token
* emits a `Transfer` event
*/
function mint(address _to, uint256 _amount) external;
/**
* @dev burn tokens on a wallet
* In case the `account` address has not enough free tokens (unfrozen tokens)
* but has a total balance higher or equal to the `value` amount
* the amount of frozen tokens is reduced in order to have enough free tokens
* to proceed the burn, in such a case, the remaining balance on the `account`
* is 100% composed of frozen tokens post-transaction.
* @param _userAddress Address to burn the tokens from.
* @param _amount Amount of tokens to burn.
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event if `_amount` is higher than the free balance of `_userAddress`
* emits a `Transfer` event
*/
function burn(address _userAddress, uint256 _amount) external;
/**
* @dev recovery function used to force transfer tokens from a
* lost wallet to a new wallet for an investor.
* @param _lostWallet the wallet that the investor lost
* @param _newWallet the newly provided wallet on which tokens have to be transferred
* @param _investorOnchainID the onchainID of the investor asking for a recovery
* This function can only be called by a wallet set as agent of the token
* emits a `TokensUnfrozen` event if there is some frozen tokens on the lost wallet if the recovery process is successful
* emits a `Transfer` event if the recovery process is successful
* emits a `RecoverySuccess` event if the recovery process is successful
* emits a `RecoveryFails` event if the recovery process fails
*/
function recoveryAddress(
address _lostWallet,
address _newWallet,
address _investorOnchainID
) external returns (bool);
/**
* @dev function allowing to issue transfers in batch
* Require that the msg.sender and `to` addresses are not frozen.
* Require that the total value should not exceed available balance.
* Require that the `to` addresses are all verified addresses,
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _toList The addresses of the receivers
* @param _amounts The number of tokens to transfer to the corresponding receiver
* emits _toList.length `Transfer` events
*/
function batchTransfer(address[] calldata _toList, uint256[] calldata _amounts) external;
/**
* @dev function allowing to issue forced transfers in batch
* Require that `_amounts[i]` should not exceed available balance of `_fromList[i]`.
* Require that the `_toList` addresses are all verified addresses
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_fromList.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _fromList The addresses of the senders
* @param _toList The addresses of the receivers
* @param _amounts The number of tokens to transfer to the corresponding receiver
* This function can only be called by a wallet set as agent of the token
* emits `TokensUnfrozen` events if `_amounts[i]` is higher than the free balance of `_fromList[i]`
* emits _fromList.length `Transfer` events
*/
function batchForcedTransfer(
address[] calldata _fromList,
address[] calldata _toList,
uint256[] calldata _amounts
) external;
/**
* @dev function allowing to mint tokens in batch
* Require that the `_toList` addresses are all verified addresses
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_toList.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _toList The addresses of the receivers
* @param _amounts The number of tokens to mint to the corresponding receiver
* This function can only be called by a wallet set as agent of the token
* emits _toList.length `Transfer` events
*/
function batchMint(address[] calldata _toList, uint256[] calldata _amounts) external;
/**
* @dev function allowing to burn tokens in batch
* Require that the `_userAddresses` addresses are all verified addresses
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses of the wallets concerned by the burn
* @param _amounts The number of tokens to burn from the corresponding wallets
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `Transfer` events
*/
function batchBurn(address[] calldata _userAddresses, uint256[] calldata _amounts) external;
/**
* @dev function allowing to set frozen addresses in batch
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses for which to update frozen status
* @param _freeze Frozen status of the corresponding address
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `AddressFrozen` events
*/
function batchSetAddressFrozen(address[] calldata _userAddresses, bool[] calldata _freeze) external;
/**
* @dev function allowing to freeze tokens partially in batch
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses on which tokens need to be frozen
* @param _amounts the amount of tokens to freeze on the corresponding address
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `TokensFrozen` events
*/
function batchFreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external;
/**
* @dev function allowing to unfreeze tokens partially in batch
* IMPORTANT : THIS TRANSACTION COULD EXCEED GAS LIMIT IF `_userAddresses.length` IS TOO HIGH,
* USE WITH CARE OR YOU COULD LOSE TX FEES WITH AN "OUT OF GAS" TRANSACTION
* @param _userAddresses The addresses on which tokens need to be unfrozen
* @param _amounts the amount of tokens to unfreeze on the corresponding address
* This function can only be called by a wallet set as agent of the token
* emits _userAddresses.length `TokensUnfrozen` events
*/
function batchUnfreezePartialTokens(address[] calldata _userAddresses, uint256[] calldata _amounts) external;
/**
* @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 / 1 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* balanceOf() and transfer().
*/
function decimals() external view returns (uint8);
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the address of the onchainID of the token.
* the onchainID of the token gives all the information available
* about the token and is managed by the token issuer or his agent.
*/
function onchainID() external view returns (address);
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the TREX version of the token.
* current version is 3.0.0
*/
function version() external view returns (string memory);
/**
* @dev Returns the Identity Registry linked to the token
*/
function identityRegistry() external view returns (IIdentityRegistry);
/**
* @dev Returns the Compliance contract linked to the token
*/
function compliance() external view returns (IModularCompliance);
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() external view returns (bool);
/**
* @dev Returns the freezing status of a wallet
* if isFrozen returns `true` the wallet is frozen
* if isFrozen returns `false` the wallet is not frozen
* isFrozen returning `true` doesn't mean that the balance is free, tokens could be blocked by
* a partial freeze or the whole token could be blocked by pause
* @param _userAddress the address of the wallet on which isFrozen is called
*/
function isFrozen(address _userAddress) external view returns (bool);
/**
* @dev Returns the amount of tokens that are partially frozen on a wallet
* the amount of frozen tokens is always <= to the total balance of the wallet
* @param _userAddress the address of the wallet on which getFrozenTokens is called
*/
function getFrozenTokens(address _userAddress) external view returns (uint256);
}
IBasicFrictionlessToken.sol 53 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { IToken } from "@ERC-3643/token/IToken.sol";
/**
* @title IBasicFrictionlessToken - Represents the base interface for Frictionless protocol tokens.
* @author Frictionless Group Holdings S.à.r.l
* @notice The IBasicFrictionlessToken Represents the base interface for Frictionless protocol tokens, this interface is used to determine a token type.
*/
interface IBasicFrictionlessToken is IToken {
/**
* @dev Enumeration to represent each of the tokens in the Frictionless protocol.
*/
enum FrictionlessTokenTypes {
NONE,
FUND_DEPOSIT_TOKEN, // IFrictionlessFundDepositToken
DIGITAL_SECURITY_TOKEN, // IFrictionlessDigitalSecurityToken
ON_CHAIN_ASSET_TOKEN // IFrictionlessOnChainAssetToken
}
/// @dev error thrown if an attempt to set an invalid token type during function `setFrictionlessTokenType`
error BasicFrictionlessTokenUnableToUpdateFrictionlessTokenType();
/**
* @dev Sets the token type according to the specified enumeration
* @param newTokenType_ the token type to set
*/
function setFrictionlessTokenType(FrictionlessTokenTypes newTokenType_) external;
/**
* @dev Returns the token type according to the specified enumeration
* @return FrictionlessTokenTypes the token type according to the specified enumeration
*/
function getFrictionlessTokenType() external view returns (FrictionlessTokenTypes);
}
IFrictionlessDigitalSecurityToken.sol 116 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS
* GROUP HOLDINGS S.à.r.l OR ANY OF ITS SUBSIDIARIES 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.16;
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title IFrictionlessDigitalSecurityToken - The permissioned & transferable digital security which represents the future cash flow from the `FrictionlessOnChainAssetToken`.
* @author Frictionless Group Holdings S.à.r.l
* @notice This is the permissioned & transferable digital security which represents the future cash flow from the `FrictionlessOnChainAssetToken` and is purchased by
* the Investor using `FrictionlessFundDepositTokens`. These digital securities are permissioned and transferable between permissioned Investors in a permissioned secondary market.
* This token is linked to the `FrictionlessOnChainAssetToken` and denominated in a FIAT currency at a future date for settlement.
*/
interface IFrictionlessDigitalSecurityToken is IBasicFrictionlessToken {
// @dev Enumeration to represent the type of the digital security, either a coupon (yield) or strip (principal)
enum FrictionlessDigitalSecurityTokenType {
COUPON,
STRIP
}
/**
* @dev Struct which represents the immutable data in the Token. Once set it cannot be modified.
* @param baseCurrency the baseCurrency is the FIAT denomination of the digital security, this is the currency the `FrictionlessOnChainAssetToken` is issued in.
* @param tokenType the type of the token as defined in the enum
* @param onChainAssetAddress the address of the `FrictionlessOnChainAssetToken` for which this token is a future cash distribution.
*/
struct FDSImmutableData {
string baseCurrency;
FrictionlessDigitalSecurityTokenType tokenType;
address onChainAssetAddress;
}
/**
* @dev Struct which represents the updatable data in the Token. This data can be modified by the Agent only.
* @param maturesOn the maturity date of the digital security, it can be updated if there are delays in payment or at the request of the calculating agent.
*/
struct FDSMutableData {
uint256 maturesOn;
}
/// @dev error throw if there is an attempt to modify the immutable data.
error FrictionlessDigitalSecurityTokenInitDataHasAlreadyBeenSet();
/// @dev error throw if there is an attempt to set zero decimals.
error FrictionlessDigitalSecurityTokenZeroDecimals();
/**
* @dev Sets the immutable data for the `FrictionlessDigitalSecurityToken`
* @param initData the immutable data for the `FrictionlessDigitalSecurityToken`
*/
function setInitData(FDSImmutableData calldata initData) external;
/**
* @dev Sets the updatable data for the `FrictionlessDigitalSecurityToken`
* @param mutableData the updatable data for the `FrictionlessDigitalSecurityToken`
*/
function setUpdateData(FDSMutableData calldata mutableData) external;
/**
* @dev Sets the custodian URI for the token
* @param custodianURI the custodian URI for the token
*/
function setCustodianURI(string calldata custodianURI) external;
/**
* @dev Sets the decimals value for the token
* @param decimals the decimals value for the token
*/
function setDecimals(uint8 decimals) external;
/**
* @dev Get the baseCurrency is the FIAT denomination of the digital security, this is the currency the `FrictionlessOnChainAssetToken` is issued in.
* @return the baseCurrency is the FIAT denomination of the digital security, this is the currency the `FrictionlessOnChainAssetToken` is issued in.
*/
function getCurrency() external view returns (string memory);
/**
* @dev Get the type of the token as defined in the enum `FrictionlessDigitalSecurityTokenType`.
* @return the type of the token as defined in the enum.
*/
function getTokenType() external view returns (FrictionlessDigitalSecurityTokenType);
/**
* @dev Get the onChainAssetAddress the address of the `FrictionlessOnChainAssetToken` for which this token is a future cash distribution.
* @return onChainAssetAddress the address of the `FrictionlessOnChainAssetToken` for which this token is a future cash distribution.
*/
function getOnChainAssetAddress() external view returns (address);
/**
* @dev Get the maturity date of the digital security.
* @return the maturity date of the digital security.
*/
function getMaturesOn() external view returns (uint256);
/**
* @dev Returns the custodian URI of the token
*/
function custodianURI() external view returns (string memory);
}
IFrictionlessFundDepositToken.sol 71 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title FrictionlessFundDepositToken - A Fund Deposit Token represents a permissioned Investors FIAT contribution to a specific fund IBAN in a denominated FIAT currency.
* @author Frictionless Group Holdings S.à.r.l
* @notice A Fund Deposit Token represents a permissioned Investors FIAT contribution to a specific fund IBAN in a denominated FIAT currency.
* The Fund Deposit Token is used as a means of payment and settlement. The Fund Deposit Token can only be transferred between permissioned Investors in the fund.
* A daily attestation of the fund IBAN serves to prove the 1:1 backing with FIAT.
* Exclusively under Frictionless Markets S.à.r.l issuance terms Investors holding a `FrictionlessFundDepositToken` have the legal right to the FIAT value held in the fund IBAN account.
*/
interface IFrictionlessFundDepositToken is IBasicFrictionlessToken {
/**
* @dev Struct which represents the immutable data in the Token. Once set it cannot be modified.
* @param currency the FIAT denomination of the deposit token.
* @param description the description of the deposit token
* @param fundIBAN the IBAN which Frictionless Markets S.à.r.l holds a matching FIAT currency ledger with a G-SIB for this currency, attestations are provided on this IBAN.
*/
struct FFDImmutableData {
string currency;
string description;
string fundIBAN;
}
/// @dev error throw if there is an attempt to modify the immutable data.
error FrictionlessFundDepositTokenUnableToUpdateInitData();
/**
* @dev Sets the immutable data for the `FrictionlessFundDepositToken`
* @param initData the immutable data for the `FrictionlessFundDepositToken`
*/
function setInitData(FFDImmutableData calldata initData) external;
/**
* @dev Get the currency the FIAT denomination of the deposit token.
* @return the currency the FIAT denomination of the deposit token.
*/
function getCurrency() external view returns (string memory);
/**
* @dev Get the description the description of the deposit token.
* @return the description the description of the deposit token
*/
function getDescription() external view returns (string memory);
/**
* @dev Get the IBAN which Frictionless Markets S.à.r.l holds a matching FIAT currency ledger with a G-SIB for this currency, attestations are provided on this IBAN.
* This is restricted to onlyAgent roles.
* @return the IBAN which Frictionless Markets S.à.r.l holds a matching FIAT currency ledger with a G-SIB for this currency, attestations are provided on this IBAN.
*/
function getFundIBAN() external returns (string memory);
}
IFrictionlessOnChainAssetToken.sol 214 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title FrictionlessOnChainAssetToken is the extension of the ERC-3643 Token to represent OnChain Assets
* @author Frictionless Group Holdings S.à.r.l
* @notice Implementation of the storage of the underlying OnChain Asset and it's data.
*/
interface IFrictionlessOnChainAssetToken is IBasicFrictionlessToken {
/// @dev Enum for the schedule of the payments by the Manager, either pro_rat or coupon/bullet style.
enum FrictionlessOnChainAssetSchedule {
// The Manager will make payments for the `FrictionlessOnChainAssetToken` on an coupon_only basis, with a bullet payment for the principal investment.
SCHEDULE_COUPON_ONLY,
// The Manager will make pro-rata payments for the `FrictionlessOnChainAssetToken` for both the principal investment and the coupon.
SCHEDULE_PRO_RATA
}
/// @dev Enum for the periodicity of payments by the Manager
enum FrictionlessOnChainAssetPaymentFrequency {
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made daily
PAYMENT_FREQUENCY_DAILY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made weekly
PAYMENT_FREQUENCY_WEEKLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made monthly
PAYMENT_FREQUENCY_MONTHLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made quarterly
PAYMENT_FREQUENCY_QUARTERLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made semi-annually
PAYMENT_FREQUENCY_SEMI_ANNUALLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made annually
PAYMENT_FREQUENCY_ANNUALLY,
// Payments from the Manager for the `FrictionlessOnChainAssetToken` are made once
PAYMENT_FREQUENCY_SINGLE
}
/// @dev Enum for the yield for this `FrictionlessOnChainAssetToken` is a fixed/floating rate
enum FrictionlessOnChainAssetYieldType {
// The yield for this `FrictionlessOnChainAssetToken` is a fixed rate
YIELD_FIXED,
// The yield for this `FrictionlessOnChainAssetToken` is a floating rate
YIELD_FLOATING
}
/// @dev Enum for the price quote status obtained at auction
enum FrictionlessOnChainAssetPriceStatus {
// The `FrictionlessOnChainAssetToken` did not receive enough offers at the offer price
PRICE_QUOTE_STATUS_UNDER_SUBSCRIBED,
// The aggregate bid at auction matched the offer
PRICE_QUOTE_STATUS_PRICED_AT_PAR,
// The aggregate bid at auction is lower than the offer
PRICE_QUOTE_STATUS_PRICED_AT_DISCOUNT,
// The aggregate bid at auction is higher than the offer
PRICE_QUOTE_STATUS_PRICED_AT_PREMIUM
}
/// @dev Enum for the current status of the `FrictionlessOnChainAssetToken`. Updated over time by the Treasury
enum FrictionlessOnChainAssetStatus {
// Status reserved for `FrictionlessOnChainAssetToken` that are MINTED onChain
STATUS_MINTED,
// Status reserved for `FrictionlessOnChainAssetToken` that are fully purchased, which means they have minted the digital securities.
STATUS_PURCHASED,
// Status reserved for `FrictionlessOnChainAssetToken` that have reached their maturity event
STATUS_MATURED,
// Status reserved for `FrictionlessOnChainAssetToken` that are in an impaired state. The parValue may be affected.
STATUS_IMPAIRED,
// Status reserved for `FrictionlessOnChainAssetToken` that are fully matured and have been fully redeemed.
STATUS_REDEEMED
}
/// @dev Enum for the current S&P style riskGrade of the `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Treasury/Risk Oracle.
enum FrictionlessOnChainAssetRiskGrade {
BER_AAA,
BER_AA,
BER_A,
BER_BBB,
BER_BB,
BER_B,
BER_CCC,
BER_CC,
BER_C,
BER_D,
BER_UNRATED
}
/**
* @dev The specification data for the `FrictionlessOnChainAssetToken`, this is an immutable data struct.
* @param issuedOn the date this `FrictionlessOnChainAssetToken` is issued by the legal Issuer, Frictionless Markets S.à.r.l
* @param maturityDays the number of days to maturity for this `FrictionlessOnChainAssetToken`
* @param schedule the schedule of the payments by the Manager, either pro_rat or coupon/bullet style.
* @param paymentFrequency the periodicity of payments by the Manager
* @param yieldType the yield for this `FrictionlessOnChainAssetToken` is a fixed/floating rate
* @param baseCurrency the currrency the `FrictionlessOnChainAssetToken` is issued in.
* @param stripTotal the principal amount for the `FrictionlessOnChainAssetToken`
* @param name the name for the `FrictionlessOnChainAssetToken`
* @param symbol the ticker symbol for the `FrictionlessOnChainAssetToken`
*/
struct FOCASpecData {
uint256 issuedOn;
uint256 maturityDays;
FrictionlessOnChainAssetSchedule schedule;
FrictionlessOnChainAssetPaymentFrequency paymentFrequency;
FrictionlessOnChainAssetYieldType yieldType;
string baseCurrency;
uint256 stripTotal;
string name;
string symbol;
}
/**
* @dev The issuance data for the `FrictionlessOnChainAssetToken`, this is an immutable data struct.
* @param auctionedOn the date this `FrictionlessOnChainAssetToken` is auctioned by the legal Issuer, Frictionless Markets S.à.r.l
* @param priceQuoteStatus the price quote status obtained at auction
* @param onChainAssetUUID the off-chain UUID in the graphQL for the token
* @param issuerUUID the off-chain UUID in the graphQL for the Manager issuing via the legal Issuer, Frictionless Markets S.à.r.l
* @param isin the ISIN numbre or equivalent for the `FrictionlessOnChainAssetToken`
* @param issuanceDocs the location of the issuance docs accessible via URI or the hash of the issuance docs.
* @param assetClass the Managers/Issuers definition of the underlying asset class for the `FrictionlessOnChainAssetToken`
*/
struct FOCAIssuanceData {
uint256 auctionedOn;
FrictionlessOnChainAssetPriceStatus priceQuoteStatus;
string onChainAssetUUID;
string issuerUUID;
string isin;
string issuanceDocs;
string assetClass;
}
/**
* @dev The uopdatable data for the `FrictionlessOnChainAssetToken`.
* @param maturesOn the date this `FrictionlessOnChainAssetToken` fully matures. Updatable if the underlying fund is extended.
* @param total the total value of the `FrictionlessOnChainAssetToken` (strip + yield over time). Updatable based on Manager IRRs, totalReturn, etc.
* @param status the current status of the `FrictionlessOnChainAssetToken`. Updated over time by the Treasury
* @param yield the current yield being paid on the `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Calculating Agent.
* @param riskGrade the current riskGrade of the `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Treasury/Risk Oracle.
* @param pullToParValue the calculation of the pullToPar value of this `FrictionlessOnChainAssetToken`. Updated over time by the Manager/Calculating Agent
* @param custodianAddress the address of the custodian for the `FrictionlessOnChainAssetToken`
*/
struct FOCAUpdateData {
uint256 maturesOn;
uint256 total;
FrictionlessOnChainAssetStatus status;
uint256 yield;
FrictionlessOnChainAssetRiskGrade riskGrade;
uint256 pullToParValue;
address custodianAddress;
}
/// @dev error throw if there is an attempt to modify the immutable data.
error FrictionlessOnChainAssetTokenUnableToUpdateData();
/**
* @dev Sets the specData data for the `FrictionlessOnChainAssetToken`.
* throws `FrictionlessOnChainAssetTokenUnableToUpdateData` This data is immutable, an attempt to modify will generate the error `FrictionlessOnChainAssetTokenUnableToUpdateData`
* @param specData the specData data for the `FrictionlessOnChainAssetToken`
*/
function setSpecificationData(FOCASpecData calldata specData) external;
/**
* @dev Sets the issuanceData data for the `FrictionlessOnChainAssetToken`
* throws `FrictionlessOnChainAssetTokenUnableToUpdateData` This data is immutable, an attempt to modify will generate the error `FrictionlessOnChainAssetTokenUnableToUpdateData`
* @param issuanceData the updatable data for the `FrictionlessOnChainAssetToken`
*/
function setIssuanceData(FOCAIssuanceData calldata issuanceData) external;
/**
* @dev Sets the updatable data for the `FrictionlessOnChainAssetToken`
* @param updateData the updatable data for the `FrictionlessOnChainAssetToken`
*/
function setUpdateData(FOCAUpdateData calldata updateData) external;
/**
* @dev Get the specData data for the `FrictionlessOnChainAssetToken`.
* @return the specData data for the `FrictionlessOnChainAssetToken`
*/
function getSpecificationData() external view returns (FOCASpecData memory);
/**
* @dev Get the issuanceData data for the `FrictionlessOnChainAssetToken`.
* @return the issuanceData data for the `FrictionlessOnChainAssetToken`
*/
function getIssuanceData() external view returns (FOCAIssuanceData memory);
/**
* @dev Get the updateData data for the `FrictionlessOnChainAssetToken`.
* @return the updateData data for the `FrictionlessOnChainAssetToken`
*/
function getUpdateData() external view returns (FOCAUpdateData memory);
/**
* @dev Get the currency the `FrictionlessOnChainAssetToken` is issued in.
* @return the currency the `FrictionlessOnChainAssetToken` is issued in.
*/
function getCurrency() external view returns (string memory);
}
IFrictionlessComplianceFactory.sol 197 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { ProxyBeacon } from "@solidity-lib/contracts-registry/pools/proxy/ProxyBeacon.sol";
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title IFrictionlessComplianceFactory - Interface defining the upgradeable compliance factory for all tokens in the Frictionless protocol.
* @author Frictionless Group Holdings S.à.r.l
* @notice Interface defining the upgradeable compliance factory for all tokens in the Frictionless protocol.
*/
interface IFrictionlessComplianceFactory {
struct SupportedComplianceData {
uint256 maxModulesCount;
EnumerableSet.AddressSet modules;
bytes32[48] _gap;
}
struct ModularComplianceInfo {
uint256 maxModulesCount;
address[] modules;
}
/**
* @dev Structure to represent the update of modular compliance data.
* @param modularCompliance the modularCompliance contract address
* @param modulesToUpdate the array of comliance modules to associate with the modularCompliance contract
* @param isAdding true if the modules are being added, false if they are being updated
*/
struct UpdateModularComplianceData {
address modularCompliance;
ModularComplianceInfo complianceInfo;
bool isAdding;
}
/**
* @dev Structure to represent the update of modular compliance data for a given token type
* @param tokenType the type of token as defined by the `IBasicFrictionlessToken.FrictionlessTokenTypes` enumerated type
* @param modulesToUpdate the array of comliance modules to associate with the token type
* @param isAdding true if the modules are being added, false if they are being updated
*/
struct UpdateSupportedComplianceData {
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType;
ModularComplianceInfo complianceInfo;
bool isAdding;
}
/// @dev error thrown if the specified contract address is a zero address, during `init`, `setTreasuryManager`, and `updateModularComplianceImpl`
error FrictionlessComplianceFactoryZeroAddr(string);
/// @dev error thrown if the `msg.sender` is not the treasury manager during the function `deployCompliance`
error FrictionlessComplianceFactoryNotATreasuryManager(address);
/// @dev error thrown if the modular compliance is invlaid for hte token type during the function `updateModularCompliancesModules`
error FrictionlessComplianceFactoryNotAModularCompliance(address);
/// @dev error thrown if an invalid tokenType is specified during `deployCompliance`
error FrictionlessComplianceFactoryInvalidTokenType();
/// @dev error thrown if an invalid module is specified during `updateModularCompliancesModules`
error FrictionlessComplianceFactoryInvalidModularComplianceData(UpdateModularComplianceData modularComplianceData);
/**
* @dev Event emitted upon successful deployment of a compliance contract.
* @param tokenType The Frictionless token type as defined by `IBasicFrictionlessToken.FrictionlessTokenTypes`
* @param newComplianceContract The compliance contract to deploy
*/
event FrictionlessComplianceDeployed(
IBasicFrictionlessToken.FrictionlessTokenTypes indexed tokenType,
address newComplianceContract
);
/**
* @dev Sets the Treasury Manager to be the specified address.
* @param newTreasuryManager_ the address of the treasury manager to set
* throws `FrictionlessComplianceFactoryZeroAddress` if the newTreasuryManager_ is a zero address
*/
function setTreasuryManager(address newTreasuryManager_) external;
/**
* @dev Updates and upgrades the modular compliance implementation
* @param newModularComplianceImpl_ the address of the modular compliance implementation
*/
function updateModularComplianceImpl(address newModularComplianceImpl_) external;
/**
* @dev Updates the set of supported modular compliance modules.
* @param updateSupportedComplianceDataArr_ the set of supported modular compliance modules.
*/
function updateSupportedComplianceData(
UpdateSupportedComplianceData[] calldata updateSupportedComplianceDataArr_
) external;
/**
* @dev Updates the modular compliance data.
* @param updateModularComplianceDataArr_ the modular compliance data.
*/
function updateModularComplianceData(
UpdateModularComplianceData[] calldata updateModularComplianceDataArr_
) external;
/**
* @dev Deploys the compliance contract using the ProxyBeacon with the associated FrictionlessPermissionsManager contract
* @param tokenType_ The Frictionless token type as defined by `IBasicFrictionlessToken.FrictionlessTokenTypes`
* @return the address of the deployed compliance contract for the specified Frictionless token type
* throws `FrictionlessComplianceFactoryNotATreasuryManager` if the msg.sender is not the treasury manager
* emits FrictionlessComplianceDeployed event upon successful deployment of the compliance contract.
*/
function deployCompliance(IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_) external returns (address);
/**
* @dev returns the address of the treasuryManager
* @return the address of the treasuryManager
*/
function treasuryManager() external view returns (address);
/**
* @dev returns the ProxyBeacon of the ModularCompliance
* @return the ProxyBeacon of the ModularCompliance
*/
function modularComplianceBeacon() external view returns (ProxyBeacon);
/**
* @dev returns the address of the ModularCompliance
* @return the address of the ModularCompliance
*/
function getModularComplianceImpl() external view returns (address);
/**
* @dev returns the `FrictionlessTokenTypes` which is bound by the ModularCompliance
* @param modularComplianceAddr_ the address of the ModularComplianceImpl
* @return the address of the ModularCompliance
*/
function getModularComplianceTokenType(
address modularComplianceAddr_
) external view returns (IBasicFrictionlessToken.FrictionlessTokenTypes);
/**
* @dev returns the amount of supported compliances ModularCompliance for the specified tokenType_
* @param tokenType_ the type of token as defined by the `IBasicFrictionlessToken.FrictionlessTokenTypes` enumerated type
* @return the amount of supported compliances
*/
function getSupportedComplianceModulesCount(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_
) external view returns (uint256);
/**
* @dev returns the array of supported compliances ModularCompliance for the specified tokenType_
* @param tokenType_ the type of token as defined by the `IBasicFrictionlessToken.FrictionlessTokenTypes` enumerated type
* @return the array of supported compliances
*/
function getSupportedComplianceModules(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_
) external view returns (address[] memory);
function getSupportedComplianceInfo(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_
) external view returns (ModularComplianceInfo memory);
/**
* @dev returns true if the compliance module supports the Frictionless token type, otherwise false
* @param tokenType_ the type of token as defined by the `IBasicFrictionlessToken.FrictionlessTokenTypes` enumerated type
* @param moduleToCheck_ the address of the modular compliance contract to verify
* @return true if the compliance module supports the Frictionless token type, otherwise false
*/
function isSupportedComplianceModule(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType_,
address moduleToCheck_
) external view returns (bool);
/**
* @dev Returns true if the address provided is a ModularCompliance contract
* @param modularComplianceAddr_ the address of the ModularCompliance contract
* @return true if the address provided is a ModularCompliance contract, otherwise false
*/
function isModularCompliance(address modularComplianceAddr_) external view returns (bool);
}
IFrictionlessTokensFactory.sol 136 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { IFrictionlessDigitalSecurityToken } from "@interface/IFrictionlessDigitalSecurityToken.sol";
import { IFrictionlessFundDepositToken } from "@interface/IFrictionlessFundDepositToken.sol";
import { IFrictionlessOnChainAssetToken } from "@interface/IFrictionlessOnChainAssetToken.sol";
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
/**
* @title IFrictionlessComplianceFactory - Interface defining the token factory for all tokens in the Frictionless protocol.
* @author Frictionless Group Holdings S.à.r.l
* @notice Interface defining the token factory for all tokens in the Frictionless protocol.
*/
interface IFrictionlessTokensFactory {
/**
* @dev Struct to represent the base contract data to deploy a Frictionless token contract.
* @param implementationAuthority the address of the implementationAuthority contract
* @param identityRegistry the address of the OnChainId IdentityRegistry contract
* @param compliance the address of the relevant compliance contract for the given Frictionless token.
* @param onChainId the address of the onChainId of the PROTOCOL_ADMIN
* @param tokenName the name of the token
* @param tokenSymbol the ticker for the token
*/
struct BaseTokenInitParams {
address implementationAuthority;
address identityRegistry;
address compliance;
address onChainId;
string tokenName;
string tokenSymbol;
}
/// @dev error thrown if an attempt to set a zero address contract during function `setTreasuryManager`
error FrictionlessTokensFactoryZeroAddress();
/// @dev error thrown if the `msg.sender` is not the treasury manager during the functions `deployFundDepositToken`, `deployDigitalSecurityToken`, or `deployOnChainAssetToken`
error FrictionlessTokensFactoryNotATreasuryManager(address);
/**
* @dev Event emitted upon successful deployment of a compliance contract.
* @param tokenType The Frictionless token type as defined by `IBasicFrictionlessToken.FrictionlessTokenTypes`
* @param newTokenContract The token contract to deploy
*/
event FrictionlessTokenDeployed(
IBasicFrictionlessToken.FrictionlessTokenTypes indexed tokenType,
address newTokenContract
);
/**
* @dev Sets the Treasury Manager to be the specified address.
* @param newTreasuryManager_ the addresses of the treasury manager to set
* throws `FrictionlessTokensFactoryZeroAddress` if the newTreasuryManager_ is a zero address
*/
function setTreasuryManager(address newTreasuryManager_) external;
/**
* @dev Deploys the `FrictionlessFundDepositToken` contract as a proxy
* @param tokenOwner_ The owner of the deployed contract
* @param baseTokenInitParams_ the base contract data to deploy a Frictionless token contract
* @param initData_ the immutable data for the `FrictionlessFundDepositToken`
* @return tokenProxyAddr_ the address of the deployed token contract `FrictionlessFundDepositToken`
* throws `FrictionlessTokensFactoryNotATreasuryManager` if the msg.sender is not the treasury manager
* emits `FrictionlessTokenDeployed` event upon successful deployment of the token contract.
*/
function deployFundDepositToken(
address tokenOwner_,
BaseTokenInitParams calldata baseTokenInitParams_,
IFrictionlessFundDepositToken.FFDImmutableData calldata initData_
) external returns (address tokenProxyAddr_);
/**
* @dev Deploys the `FrictionlessDigitalSecurityToken` contract as a proxy
* @param tokenOwner_ The owner of the deployed contract
* @param baseTokenInitParams_ the base contract data to deploy a Frictionless token contract
* @param initData_ the immutable data for the `FrictionlessDigitalSecurityToken`
* @param updateData_ the mutable data for the `FrictionlessDigitalSecurityToken`
* @return tokenProxyAddr_ the address of the deployed token contract `FrictionlessDigitalSecurityToken`
* throws `FrictionlessTokensFactoryNotATreasuryManager` if the msg.sender is not the treasury manager
* emits `FrictionlessTokenDeployed` event upon successful deployment of the token contract.
*/
function deployDigitalSecurityToken(
address tokenOwner_,
BaseTokenInitParams calldata baseTokenInitParams_,
IFrictionlessDigitalSecurityToken.FDSImmutableData calldata initData_,
IFrictionlessDigitalSecurityToken.FDSMutableData calldata updateData_
) external returns (address tokenProxyAddr_);
/**
* @dev Deploys the `FrictionlessOnChainAssetToken` contract as a proxy
* @param tokenOwner_ The owner of the deployed contract
* @param baseTokenInitParams_ the base contract data to deploy a Frictionless token contract
* @param specData_ the immutable specification data for the `FrictionlessOnChainAssetToken`
* @param issuanceData_ the immutable issuance data for the `FrictionlessOnChainAssetToken`
* @param updateData_ the mutable update data for the `FrictionlessOnChainAssetToken`
* @return tokenProxyAddr_ the address of the deployed token contract `FrictionlessOnChainAssetToken`
* throws `FrictionlessTokensFactoryNotATreasuryManager` if the msg.sender is not the treasury manager
* emits `FrictionlessTokenDeployed` event upon successful deployment of the token contract.
*/
function deployOnChainAssetToken(
address tokenOwner_,
BaseTokenInitParams calldata baseTokenInitParams_,
IFrictionlessOnChainAssetToken.FOCASpecData calldata specData_,
IFrictionlessOnChainAssetToken.FOCAIssuanceData calldata issuanceData_,
IFrictionlessOnChainAssetToken.FOCAUpdateData calldata updateData_
) external returns (address tokenProxyAddr_);
/**
* @dev returns the address of the treasuryManager
* @return the address of the treasuryManager
*/
function treasuryManager() external view returns (address);
/**
* @dev Checks whether a given token address is an existing frictionless token
* @param tokenAddr_ the address of the token to check
* @return A boolean indicating whether the token is an existing frictionless token
*/
function existingFrictionlessTokens(address tokenAddr_) external view returns (bool);
}
IFrictionlessPermissionsManager.sol 150 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
/**
* @title IFrictionlessPermissionsManager - Manages the permission of participants in the Frictionless protocol
* @author Frictionless Group Holdings S.à.r.l
* @notice The IFrictionlessPermissionsManager is responsible for the management of permission of the various participants in
* the Frictionless protocol. The roles and responsibilities are defined in the public README for the Frictionless protocol at
* https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/blob/main/README.md?ref_type=heads#roles-responsibilities
*/
interface IFrictionlessPermissionsManager {
/// @dev Enum of the Frictionless protocol participants.
enum FrictionlessPermissionedUser {
PROTOCOL_TREASURY,
PERMISSIONED_CUSTODIAN,
PERMISSIONED_INVESTOR,
PERMISSIONED_MANAGER,
PERMISSIONED_CALCULATING_AGENT,
PERMISSIONED_TRANSFER_AGENT,
PERMISSIONED_FUND_ACCOUNTANT
}
/// @dev throws if specific address is zero.
error FrictionlessIsZeroAddress(string);
/// @dev throws if treasury tries to add or remove treasury.
error FrictionlessInvalidPermissionForTreasury();
/// @dev throws if user is not a permissioned investor
error FrictionlessUserIsNotPermssionedInvestor();
/**
* @dev Emitted when a user is added to the Frictionless protocol. This event is emitted by the `addUser` function.
* @param userIdentity the address of the user's OnChainId (Identity)
* @param userType the type of the user as per the enum
* @param claimURI the URI of the off-chain claim for the user. i.e. The Frictionless Markets graphQL endpoint
*/
event FrictionlessPermissionedUserAdded(address userIdentity, uint256 userType, string claimURI);
/**
* @dev Emitted when a user is registered in the Frictionless protocol. This event is emitted by the `registerIdentity` function.
* @param userAddress the address of the user's wallet to register
* @param userISOCountry the ISO 3166-1 numeric code of the user, can be the place of residence or the location KYC/AML onboarding was undertaken.
*/
event FrictionlessPermissionedUserRegistered(address userAddress, uint16 userISOCountry);
/**
* @dev Emitted when a user is removed in the Frictionless protocol. This event is emitted by the `removeUser` function.
* @param userAddress the address of the user's wallet to register
*/
event FrictionlessPermissionedUserRemoved(address userAddress);
/// @dev the internal struct defining a Claim for a PERMISSIONED_USER in the protocol. Used to submit claims for the OnChainId by the ClaimIssuer.
struct Claim {
address issuer;
uint256 topic;
uint8 scheme;
address identity;
bytes signature;
bytes data;
}
/**
* @dev Validates if a wallet address is permissioned in the Frictionless protocol
* @param userAddress the wallet address to verify
* @return true if the address is permissioned in the Frictionless Protocol.
*/
function isPermissioned(address userAddress) external view returns (bool);
/**
* @dev Registers a users wallet address as an OnChainId (Identity) to the Frictionless protocol.
* This Identity is used when permissioning a user to the protocol by invoking the addUser function later.
* @param userAddress the address of the user's wallet to register
* @param userISOCountry the ISO 3166-1 numeric code of the user, can be the place of residence or the location KYC/AML onboarding was undertaken.
* requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN)
* @return address the address of the user's OnChainId (Identity) with the associated claims.
*/
function registerIdentity(address userAddress, uint16 userISOCountry) external returns (address);
/**
* @dev Gets a users OnChainId (Identity) in the Frictionless protocol.
* @param userAddress the address of the user's wallet to register
* requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN)
* @return address the address of the user's OnChainId (Identity) with the associated claims.
*/
function getIdentity(address userAddress) external returns (address);
/**
* @dev Get the signed claimData message to be used in the addUser function.
* The message must be signed using the PK of the ClaimIssuer (PROTOCOL_ADMIN)
* @param userIdentity the address of the user's OnChainId (Identity)
* @param userType the type of the user as per the enum
* @return signed claimData message to be used in the addUser unction once signed by the ClaimIssuer PK.
*/
function getClaimMsgHash(
address userIdentity,
IFrictionlessPermissionsManager.FrictionlessPermissionedUser userType
) external view returns (bytes32);
/**
* @dev verify if the userAddress is permissioned in the Frictionless protocol and has a valid claim
* @param userAddress the address of the user's wallet to verify
* @param userType the type of the user as per the enum
* @return true if a valid permissioned user and has a valid claim, otherwise false.
*/
function hasClaim(address userAddress, FrictionlessPermissionedUser userType) external view returns (bool);
/**
* @dev Adds a user's OnChainId (Identity) to the Frictionless protocol along with its associated claim data.
* The Identity is created by invoking the registerIdentity function first.
* @param userIdentity the address of the user's OnChainId (Identity)
* @param userType the type of the user as per the enum
* @param claimSignature the signed claimData by the ClaimIssuer
* @param claimURI the URI of the off-chain claim for the user. i.e. The Frictionless Markets graphQL endpoint
* requires The msg.sender to be the Owner if the userType is the PROTOCOL_TREASURY
* requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN) to add any user
* @return address the address of the user's OnChainId (Identity) with the associated claims.
*/
function addUser(
address userIdentity,
FrictionlessPermissionedUser userType,
bytes memory claimSignature,
string memory claimURI
) external returns (address);
/**
* @dev Removes a user from the Frictionless protocol along with its associated claim data.
* @param userAddress the address of the user's wallet
* requires The msg.sender to have the TREX Agent permissions (PROTOCOL_TREASURY or PROTOCOL_ADMIN) to remove any user
* @return true if the user is removed from the Frictionless protocol along with its associated claim data, otherwise false.
*/
function removeUser(address userAddress) external returns (bool);
}
IFrictionlessTreasuryManager.sol 232 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { IBasicFrictionlessToken } from "@interface/IBasicFrictionlessToken.sol";
import { IFrictionlessDigitalSecurityToken } from "@interface/IFrictionlessDigitalSecurityToken.sol";
import { IFrictionlessFundDepositToken } from "@interface/IFrictionlessFundDepositToken.sol";
import { IFrictionlessOnChainAssetToken } from "@interface/IFrictionlessOnChainAssetToken.sol";
/**
* @title IFrictionlessTreasuryManager - Manages the minting, transfer and burning of all tokens in the Frictionless protocol
* @author Frictionless Group Holdings S.à.r.l
* @notice The IFrictionlessTreasuryManager is responsible for all token operations, minting, transferring and burning in
* the Frictionless protocol. The tokens and their lifecycles are defined in the public README for the Frictionless protocol at
* https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/tree/main?ref_type=heads#tokens-overview
*/
interface IFrictionlessTreasuryManager {
/**
* @dev Structure that encapsulates both the implAuthority and the compliance for the specific token.
* @param implAuthority the contract address for the implementation authority associated with the specific Frictionless token type.
* @param tokenType the Frictionless token type as specified by the enumeration `IBasicFrictionlessToken.FrictionlessTokenTypes`
*/
struct FrictionlessTokenInitData {
address implAuthority;
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType;
}
/// @dev throws if specific address is zero.
error FrictionlessIsZeroAddress(string);
/**
* @dev Event emitted when a `FrictionlessFundDeposit`, `FrictionlessDigitalSecurity` or `FrictionlessOnChainAsset` is minted.
* @param token the address of the token minted
* @param tokenName the name of the token
* @param tokenSymbol the token symbol
* @param amount the amount of the token minted
* @param toAddress the address the token was minted to
*/
event FrictionlessTokenMinted(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType,
address token,
string tokenName,
string tokenSymbol,
uint256 amount,
address toAddress
);
/**
* @dev Event emitted when a `FrictionlessFundDeposit`, `FrictionlessDigitalSecurity` or `FrictionlessOnChainAsset` is transferred.
* @param token the address of the token transferred
* @param amount the amount of the token transferred
* @param fromAddress the address the token was transferred from
* @param toAddress the address the token was transferred to
*/
event FrictionlessTokenTransferred(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType,
address token,
uint256 amount,
address fromAddress,
address toAddress
);
/**
* @dev Event emitted when a `FrictionlessFundDeposit`, `FrictionlessDigitalSecurity` or `FrictionlessOnChainAsset` is burned.
* @param token the address of the token burned
* @param amount the amount of the token burned
* @param fromAddress the address the token was burned from
*/
event FrictionlessTokenBurned(
IBasicFrictionlessToken.FrictionlessTokenTypes tokenType,
address token,
uint256 amount,
address fromAddress
);
/// @dev error throw if the function caller is not a PROTOCOL_TREASURY address. Thrown during the `mintFundDepositForTreasury`
error FrictionlessTreasuryManagerNotAProtocolTreasury(address);
/// @dev error throw if the FundDepositToken for specified currency and fundIBAN already exists
error FrictionlessTreasuryManagerFundDepositTokenAlreadyExists(string currency, string fundIBAN);
/// @dev error throw if the data for the token init data `FrictionlessTokenInitData` is invalid. Thrown during the `_setTokensInitData`
error FrictionlessTreasuryManagerInvalidTokenInitData(FrictionlessTokenInitData);
/// @dev error throw if the data for the token init data `FrictionlessTokenInitData` is already set. Thrown during the `_setTokensInitData`
error FrictionlessTreasuryManagerUnableToUpdateTokenInitData(IBasicFrictionlessToken.FrictionlessTokenTypes);
/// @dev error throw if the data for the IFrictionlessFundDepositToken is invalid. Thrown during the `mintFundDepositForTreasury`
error FrictionlessTreasuryManagerInvalidDepositData(IFrictionlessFundDepositToken.FFDImmutableData);
/// @dev error throw if the data for the IFrictionlessDigitalSecurityToken is invalid. Thrown during the `mintDigitalSecurity`
error FrictionlessTreasuryManagerInvalidFDSImmutableData(IFrictionlessDigitalSecurityToken.FDSImmutableData);
/// @dev error throw if the data for the IFrictionlessDigitalSecurityToken is invalid. Thrown during the `mintOnChainAsset`
error FrictionlessTreasuryManagerInvalidFOCASpecData(IFrictionlessOnChainAssetToken.FOCASpecData);
/// @dev error throw if the data for the IFrictionlessDigitalSecurityToken is invalid. Thrown during the `mintOnChainAsset`
error FrictionlessTreasuryManagerInvalidFOCAIssuanceData(IFrictionlessOnChainAssetToken.FOCAIssuanceData);
/**
* @dev See {PausableUpgradeable-_pause}
*/
function pause() external;
/**
* @dev See {PausableUpgradeable-_unpause}
*/
function unpause() external;
/**
* @dev Sets and associates the implementation authority with the associated token type
* @param initDataArr_ the `FrictionlessTokenInitData` configuration associating the implementation authority with the associated token type.
*/
function setTokensInitData(FrictionlessTokenInitData[] calldata initDataArr_) external;
/**
* @dev Mints a Fund Deposit Token in the specified currency/IBAN pair. This function is invoked to create the genesis mint of the
* deposit token in the PROTOCOL_TREASURY.
* @param depositData the immutable deposit data for the token
* @param treasuryAddress the address of the treasury, which receives the deposit tokens
* @param amount the amount of tokens
* @return address of the token minted
* emits `FrictionlessTokenMinted` event
* throws error `FrictionlessTreasuryManagerInvalidDepositData` if the deposit data is invalid.
* requires the depositData.currency to be a 3 letter currency code
* requires the depositData.description to be not empty
* requires the depositData.IBAN to be not empty
*/
function mintFundDepositForTreasury(
IFrictionlessFundDepositToken.FFDImmutableData calldata depositData,
address treasuryAddress,
uint256 amount
) external returns (address);
/**
* @dev Mints a FrictionlessDigitalSecurityToken as the future dated cash distribution from the underlying FrictionlessOnChainAssetToken.
* This function is invoked to create the genesis mint of the deposit token in the PROTOCOL_TREASURY.
* @param initData the immutable data for the token
* @param updateData the mutable data for the token
* @param amount the amount of tokens
* @param userAddress the address of the protocol user, which receives the digital security tokens
* @return address of the token minted
* emits `FrictionlessTokenMinted` event
* throws error `FrictionlessTreasuryManagerInvalidFDSImmutableData` if the initData is invalid.
* requires the initData.currency to be a 3 letter currency code
* requires the initData.onChainAssetAddress to be non 0 address
*/
function mintDigitalSecurity(
IFrictionlessDigitalSecurityToken.FDSImmutableData memory initData,
IFrictionlessDigitalSecurityToken.FDSMutableData memory updateData,
uint256 amount,
address userAddress
) external returns (address);
/**
* @dev Mints a FrictionlessOnChainAssetToken as the representation of the asset to be securitized, fractionalized & sold.
* This function is invoked to create the genesis mint of the deposit token to the PERMISSIONED_CUSTODIAN.
* @param specData the immutable data for the token
* @param issuanceData the issuance data for the token
* @param updateData the update data for the token
* @param custodianAddress the address of the protocol custodian, which receives the `FrictionlessOnChainAssetToken`
* @return address of the token minted
* emits `FrictionlessTokenMinted` event
* throws error `FrictionlessTreasuryManagerInvalidFOCASpecData` or `FrictionlessTreasuryManagerInvalidFOCAIssuanceData` if the specData or issuanceData is invalid.
*/
function mintOnChainAsset(
IFrictionlessOnChainAssetToken.FOCASpecData memory specData,
IFrictionlessOnChainAssetToken.FOCAIssuanceData memory issuanceData,
IFrictionlessOnChainAssetToken.FOCAUpdateData memory updateData,
address custodianAddress
) external returns (address);
/**
* @dev Used to increase the mint of a Frictionless token which already exists.
* @param token the address of the token
* @param userAddress the address to min the token to
* @param amount the amount of tokens to mint
* emits `FrictionlessTokenMinted` event
*/
function mintTokenForUser(address token, address userAddress, uint256 amount) external;
/**
* @dev Used to increase the mint of a Frictionless token which already exists.
* @param token the address of the token
* @param userAddressFrom the address to transfer the tokens from
* @param userAddressTo the address to transfer the tokens to
* @param amount the amount of tokens to mint
* emits `FrictionlessTokenTransferred` event
*/
function transferToken(address token, address userAddressFrom, address userAddressTo, uint256 amount) external;
/**
* @dev Used to burn an amount of Frictionless token which already exists.
* @param token the address of the token
* @param userAddress the address to burn the tokens from
* @param amount the amount of tokens to burn
* emits `FrictionlessTokenBurned` event
*/
function burnToken(address token, address userAddress, uint256 amount) external;
/**
* @dev returns the address of the fund deposit token by currency and fundIBAN
* @param currency_ the currency of the fund deposit token
* @param fundIBAN_ the fundIBAN of the fund deposit token
* @return the address of the fund deposit token for specified currency and fundIBAN
*/
function getFundDepositToken(string calldata currency_, string calldata fundIBAN_) external view returns (address);
/**
* @dev returns fund deposit token key by currency and fundIBAN
* @param currency_ the currency of the fund deposit token you need
* @param fundIBAN_ the fundIBAN of the fund deposit token you need
* @return the fund deposit token key
*/
function getFundDepositTokenKey(string memory currency_, string memory fundIBAN_) external pure returns (bytes32);
}
IFrictionlessAttestationManager.sol 214 lines
// SPDX-License-Identifier: MIT
/**
* Copyright © 2024 Frictionless Group Holdings S.à.r.l
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of the Frictionless protocol smart contracts
* (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 (including the next paragraph) shall be included in all copies
* or substantial portions of the Software.
*
* 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 FRICTIONLESS GROUP
* HOLDINGS S.à.r.l OR AN OF ITS SUBSIDIARIES 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.16;
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
/**
* @title IFrictionlessAttestationManager Contract responsible for providing attestations of the balances held in the underlying funding accounts
* for each `FrictionlessFundDepositToken`. The attestation is provided and signed by an independent 3rd party, known as the
* PERMISSIONED_FUND_ACCOUNTANT in the Frictionless protocol.
* @author Frictionless Group Holdings S.à.r.l
* @notice The IFrictionlessAttestationManager See the flow and description of the attestation workflow in the diagram at
* https://gitlab.com/dfyclabs/protocol/dfyclabs-tokens/-/raw/main/docs/img/frictionless-fund-deposit-flow-attestation.png
*/
interface IFrictionlessAttestationManager {
/**
* @dev struct to hold attestation data, which is designed to provide the most recent attestation of balance and
* verified last transaction in an attestation window.
* @param tokenAddr the address of the `FrictionlessFundDepositToken`
* @param iban the IBAN associated with the `FrictionlessFundDepositToken`
* @param currency the currency associated with the `FrictionlessFundDepositToken`
* @param reportStart the start timeframe in blocktime of the attestation window (reportEnd - reportStart)
* @param reportEnd the end timeframe in blocktime of the attestation window (reportEnd - reportStart)
* @param balance the balance as reported in the currency account
* @param lastTxHash the hash of the last transaction in the attestation window (reportEnd - reportStart)
*/
struct AttestationData {
address tokenAddr;
string iban;
string currency;
uint256 reportStart;
uint256 reportEnd;
uint256 balance;
string lastTxHash;
}
/**
* @dev struct to hold account attestation data
* @param attestationTokenAddr the address of the `FrictionlessFundDepositToken`
* @param lastAttestationDataKey the key for the last attestation data associated with the account
* @param allAttestationDataKeys set containing all attestation data keys associated with the account
*/
struct AccountAttestationData {
address attestationTokenAddr;
bytes32 lastAttestationDataKey;
EnumerableSet.Bytes32Set allAttestationDataKeys;
}
/**
* @dev Emitted when the `FrictionlessFundDepositToken` is updated in the `IFrictionlessAttestationManager`.
* @param accountAttestationKey the attestation key associated with the account
* @param newTokenAddress the updated token contract address that the `IFrictionlessAttestationManager` is aware of
* @param oldTokenAddress the previous token contract address before the update
*/
event FrictionlessFundDepositAttestationTokenUpdated(
bytes32 accountAttestationKey,
address newTokenAddress,
address oldTokenAddress
);
/// @dev thrown if msg.sender address is not a PROTOCOL_TREASURY, during `updateAttestationToken`
error FrictionlessAttestationManagerCallerNotAProtocolTreasury(address caller);
/**
* @dev Event emitted upon the confirmation of a `FrictionlessFundDepositToken` in the `IFrictionlessAttestationManager`
* @param attestationData the complete set of attestation data signed by the PERMISSIONED_FUND_ACCOUNTANT.
*/
event FrictionlessFundDepositAttestationConfirmed(AttestationData attestationData);
/// @dev thrown if tokenAddress_ address is a zero address, during `updateAttestationToken`
error FrictionlessAttestationManagerTokenZeroAddress();
/// @dev thrown if permissionManagerAddr_ address is a zero address, during `init`
error FrictionlessAttestationManagerPermissionsZeroAddress();
/// @dev thrown if the `FrictionlessFundDepositToken` has not been registered for the IBAN, currency pair.
error FrictionlessAttestationManagerInvalidToken(string iban, string currency);
/// @dev thrown if the passed `AttestationData` report is invalid.
error FrictionlessAttestationManagerInvalidReport(AttestationData attestationData);
/// @dev thrown if the attestation balance is too small, below the configurable amount.
error FrictionlessAttestationManagerBalanceTooLow(uint256 balance);
/// @dev thrown if the last transaction hash for the attestation has already been used, this avoids duplicate attestations.
error FrictionlessAttestationManagerDuplicateLastTxHash(string lastTxHash);
/// @dev thrown if the attestation cannot be confirmed, meaning the signed attestation cannot be verified.
error FrictionlessAttestationManagerInvalidAttestationSigner(address signer, bytes32 attestationHash, bytes sig);
/**
* @dev Update the token address of the `FrictionlessFundDepositToken` for
* the `currency_` and `iban_` pair.
* @param tokenAddress_ the address of deposit `FrictionlessFundDepositToken`
* @param iban_ the IBAN associated with the `FrictionlessFundDepositToken`
* @param currency_ the currency associated with the `FrictionlessFundDepositToken`
* throws `FrictionlessAttestationManagerTokenZeroAddress` if tokenAddress_ address is a zero address
* emits `FrictionlessFundDepositAttestationTokenUpdated` upon successful updating
*/
function updateAttestationToken(address tokenAddress_, string calldata iban_, string calldata currency_) external;
/**
* @dev Confirm the attestation by signing the signature, this is the proof of the attestation by the PERMISSIONED_FUND_ACCOUNTANT
* @param attestationData_ attestation data to sign
* @param sig_ the signature to sign by the PERMISSIONED_FUND_ACCOUNTANT
* throws `FrictionlessAttestationManagerNotEnoughPermissions` if the msg.sender does not have the role PERMISSIONED_FUND_ACCOUNTANT
* throws `FrictionlessAttestationManagerInvalidAttestation` if the attestation cannot be confirmed, meaning the signed attestation cannot be verified.
* emits `FrictionlessFundDepositAttestationConfirmed` upon successful signing
*/
function confirmAttestation(AttestationData calldata attestationData_, bytes calldata sig_) external;
/**
* @dev Get the minimum balance amount configured, for which an attestation can be run.
* If the balance of the attestation is below the value configured, the error will be thrown.
* The minimum allowed is 10_000 or 0.01
* @return minimum attestation balance.
*/
function minBalance() external view returns (uint256);
/**
* @dev Get minimum time (reportEnd - reportStart) in blocktime for which an attestation can be run.
* Typically this is 1 hour, and dependent on the availability of transaction data in the underlying fund account as specified by the IBAN.
* The minimum allowed is 300 seconds.
* @return minimum attestation window.
*/
function minWindow() external view returns (uint256);
/**
* @dev Get maximum time (reportEnd - reportStart) in blocktime for which an attestation can be run.
* Typically this is 30 days, aligned with the reporting as per regulation for the underlying fund and issuer of the deposit token.
* The maximum allowed is 365 days.
* @return maximum attestation window.
*/
function maxWindow() external view returns (uint256);
/**
* @dev Retrieves the keys of attestation data associated with a specific account identified by IBAN and currency.
* @param iban_ the IBAN associated with the `FrictionlessFundDepositToken`
* @param currency_ the currency associated with the `FrictionlessFundDepositToken`
* @return the array of bytes32 attestation data keys associated with the account.
*/
function getAccountAttestationDataKeys(
string calldata iban_,
string calldata currency_
) external view returns (bytes32[] memory);
/**
* @dev Retrieves the last attestation data associated with a specific account identified by IBAN and currency.
* @param iban_ the IBAN associated with the `FrictionlessFundDepositToken`
* @param currency_ the currency associated with the `FrictionlessFundDepositToken`
* @return the `AttestationData` struct representing the last attestation data associated with the account.
*/
function getAccountLastAttestationData(
string calldata iban_,
string calldata currency_
) external view returns (AttestationData memory);
/**
* @dev Retrieves the key of the last attestation data associated with a specific account identified by IBAN and currency.
* @param iban_ the IBAN associated with the `FrictionlessFundDepositToken`
* @param currency_ the currency associated with the `FrictionlessFundDepositToken`
* @return the last attestation data key associated with the account.
*/
function getAccountLastAttestationDataKey(
string calldata iban_,
string calldata currency_
) external view returns (bytes32);
/**
* @dev Retrieves attestation data by the attestation data key.
* @param attestationDataKey_ the key identifying the attestation data
* @return the AttestationData struct representing the attestation data associated with the given key.
*/
function getAttestationData(bytes32 attestationDataKey_) external view returns (AttestationData memory);
/**
* @dev Get the valid `FrictionlessFundDepositToken` for the `currency_` and `iban_` pair.
* @param iban_ the IBAN associated with the FrictionlessFundDepositToken
* @param currency_ the currency associated with the FrictionlessFundDepositToken
* @return the address of the valid `FrictionlessFundDepositToken` for the `currency_` and `iban_` pair
*/
function getTokenAddress(string memory iban_, string memory currency_) external view returns (address);
/**
* @dev Mint a new attestation, it returns hash of attestation data to sign by the PERMISSIONED_FUND_ACCOUNTANT
* @param attestationData_ the complete set of attestation data to for the PERMISSIONED_FUND_ACCOUNTANT to certify/sign.
* @return a hash of the attestationData which will be signed to confirm the attestation
*/
function getAttestationDataHash(AttestationData calldata attestationData_) external view returns (bytes32);
/**
* @dev Retrieves the attestation data key associated with a specific account identified by currency and IBAN.
* @param iban_ the IBAN associated with the `FrictionlessFundDepositToken`
* @param currency_ the currency associated with the `FrictionlessFundDepositToken`
* @return the accound attestation key.
*/
function getAccountAttestationKey(string calldata currency_, string calldata iban_) external pure returns (bytes32);
}
ITrustedIssuersRegistry.sol 162 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "@onchain-id/solidity/contracts/interface/IClaimIssuer.sol";
interface ITrustedIssuersRegistry {
/**
* this event is emitted when a trusted issuer is added in the registry.
* the event is emitted by the addTrustedIssuer function
* `trustedIssuer` is the address of the trusted issuer's ClaimIssuer contract
* `claimTopics` is the set of claims that the trusted issuer is allowed to emit
*/
event TrustedIssuerAdded(IClaimIssuer indexed trustedIssuer, uint256[] claimTopics);
/**
* this event is emitted when a trusted issuer is removed from the registry.
* the event is emitted by the removeTrustedIssuer function
* `trustedIssuer` is the address of the trusted issuer's ClaimIssuer contract
*/
event TrustedIssuerRemoved(IClaimIssuer indexed trustedIssuer);
/**
* this event is emitted when the set of claim topics is changed for a given trusted issuer.
* the event is emitted by the updateIssuerClaimTopics function
* `trustedIssuer` is the address of the trusted issuer's ClaimIssuer contract
* `claimTopics` is the set of claims that the trusted issuer is allowed to emit
*/
event ClaimTopicsUpdated(IClaimIssuer indexed trustedIssuer, uint256[] claimTopics);
/**
* @dev registers a ClaimIssuer contract as trusted claim issuer.
* Requires that a ClaimIssuer contract doesn't already exist
* Requires that the claimTopics set is not empty
* Requires that there is no more than 15 claimTopics
* Requires that there is no more than 50 Trusted issuers
* @param _trustedIssuer The ClaimIssuer contract address of the trusted claim issuer.
* @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit
* This function can only be called by the owner of the Trusted Issuers Registry contract
* emits a `TrustedIssuerAdded` event
*/
function addTrustedIssuer(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external;
/**
* @dev Removes the ClaimIssuer contract of a trusted claim issuer.
* Requires that the claim issuer contract to be registered first
* @param _trustedIssuer the claim issuer to remove.
* This function can only be called by the owner of the Trusted Issuers Registry contract
* emits a `TrustedIssuerRemoved` event
*/
function removeTrustedIssuer(IClaimIssuer _trustedIssuer) external;
/**
* @dev Updates the set of claim topics that a trusted issuer is allowed to emit.
* Requires that this ClaimIssuer contract already exists in the registry
* Requires that the provided claimTopics set is not empty
* Requires that there is no more than 15 claimTopics
* @param _trustedIssuer the claim issuer to update.
* @param _claimTopics the set of claim topics that the trusted issuer is allowed to emit
* This function can only be called by the owner of the Trusted Issuers Registry contract
* emits a `ClaimTopicsUpdated` event
*/
function updateIssuerClaimTopics(IClaimIssuer _trustedIssuer, uint256[] calldata _claimTopics) external;
/**
* @dev Function for getting all the trusted claim issuers stored.
* @return array of all claim issuers registered.
*/
function getTrustedIssuers() external view returns (IClaimIssuer[] memory);
/**
* @dev Function for getting all the trusted issuer allowed for a given claim topic.
* @param claimTopic the claim topic to get the trusted issuers for.
* @return array of all claim issuer addresses that are allowed for the given claim topic.
*/
function getTrustedIssuersForClaimTopic(uint256 claimTopic) external view returns (IClaimIssuer[] memory);
/**
* @dev Checks if the ClaimIssuer contract is trusted
* @param _issuer the address of the ClaimIssuer contract
* @return true if the issuer is trusted, false otherwise.
*/
function isTrustedIssuer(address _issuer) external view returns (bool);
/**
* @dev Function for getting all the claim topic of trusted claim issuer
* Requires the provided ClaimIssuer contract to be registered in the trusted issuers registry.
* @param _trustedIssuer the trusted issuer concerned.
* @return The set of claim topics that the trusted issuer is allowed to emit
*/
function getTrustedIssuerClaimTopics(IClaimIssuer _trustedIssuer) external view returns (uint256[] memory);
/**
* @dev Function for checking if the trusted claim issuer is allowed
* to emit a certain claim topic
* @param _issuer the address of the trusted issuer's ClaimIssuer contract
* @param _claimTopic the Claim Topic that has to be checked to know if the `issuer` is allowed to emit it
* @return true if the issuer is trusted for this claim topic.
*/
function hasClaimTopic(address _issuer, uint256 _claimTopic) external view returns (bool);
}
IClaimTopicsRegistry.sol 102 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
interface IClaimTopicsRegistry {
/**
* this event is emitted when a claim topic has been added to the ClaimTopicsRegistry
* the event is emitted by the 'addClaimTopic' function
* `claimTopic` is the required claim added to the Claim Topics Registry
*/
event ClaimTopicAdded(uint256 indexed claimTopic);
/**
* this event is emitted when a claim topic has been removed from the ClaimTopicsRegistry
* the event is emitted by the 'removeClaimTopic' function
* `claimTopic` is the required claim removed from the Claim Topics Registry
*/
event ClaimTopicRemoved(uint256 indexed claimTopic);
/**
* @dev Add a trusted claim topic (For example: KYC=1, AML=2).
* Only owner can call.
* emits `ClaimTopicAdded` event
* cannot add more than 15 topics for 1 token as adding more could create gas issues
* @param _claimTopic The claim topic index
*/
function addClaimTopic(uint256 _claimTopic) external;
/**
* @dev Remove a trusted claim topic (For example: KYC=1, AML=2).
* Only owner can call.
* emits `ClaimTopicRemoved` event
* @param _claimTopic The claim topic index
*/
function removeClaimTopic(uint256 _claimTopic) external;
/**
* @dev Get the trusted claim topics for the security token
* @return Array of trusted claim topics
*/
function getClaimTopics() external view returns (uint256[] memory);
}
IIdentityRegistryStorage.sol 197 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
import "@onchain-id/solidity/contracts/interface/IIdentity.sol";
interface IIdentityRegistryStorage {
/// events
/**
* this event is emitted when an Identity is registered into the storage contract.
* the event is emitted by the 'registerIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityStored(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity is removed from the storage contract.
* the event is emitted by the 'deleteIdentity' function
* `investorAddress` is the address of the investor's wallet
* `identity` is the address of the Identity smart contract (onchainID)
*/
event IdentityUnstored(address indexed investorAddress, IIdentity indexed identity);
/**
* this event is emitted when an Identity has been updated
* the event is emitted by the 'updateIdentity' function
* `oldIdentity` is the old Identity contract's address to update
* `newIdentity` is the new Identity contract's
*/
event IdentityModified(IIdentity indexed oldIdentity, IIdentity indexed newIdentity);
/**
* this event is emitted when an Identity's country has been updated
* the event is emitted by the 'updateCountry' function
* `investorAddress` is the address on which the country has been updated
* `country` is the numeric code (ISO 3166-1) of the new country
*/
event CountryModified(address indexed investorAddress, uint16 indexed country);
/**
* this event is emitted when an Identity Registry is bound to the storage contract
* the event is emitted by the 'addIdentityRegistry' function
* `identityRegistry` is the address of the identity registry added
*/
event IdentityRegistryBound(address indexed identityRegistry);
/**
* this event is emitted when an Identity Registry is unbound from the storage contract
* the event is emitted by the 'removeIdentityRegistry' function
* `identityRegistry` is the address of the identity registry removed
*/
event IdentityRegistryUnbound(address indexed identityRegistry);
/// functions
/**
* @dev adds an identity contract corresponding to a user address in the storage.
* Requires that the user doesn't have an identity contract already registered.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's identity contract
* @param _country The country of the investor
* emits `IdentityStored` event
*/
function addIdentityToStorage(
address _userAddress,
IIdentity _identity,
uint16 _country
) external;
/**
* @dev Removes an user from the storage.
* Requires that the user have an identity contract already deployed that will be deleted.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user to be removed
* emits `IdentityUnstored` event
*/
function removeIdentityFromStorage(address _userAddress) external;
/**
* @dev Updates the country corresponding to a user address.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user
* @param _country The new country of the user
* emits `CountryModified` event
*/
function modifyStoredInvestorCountry(address _userAddress, uint16 _country) external;
/**
* @dev Updates an identity contract corresponding to a user address.
* Requires that the user address should be the owner of the identity contract.
* Requires that the user should have an identity contract already deployed that will be replaced.
* This function can only be called by an address set as agent of the smart contract
* @param _userAddress The address of the user
* @param _identity The address of the user's new identity contract
* emits `IdentityModified` event
*/
function modifyStoredIdentity(address _userAddress, IIdentity _identity) external;
/**
* @notice Adds an identity registry as agent of the Identity Registry Storage Contract.
* This function can only be called by the wallet set as owner of the smart contract
* This function adds the identity registry to the list of identityRegistries linked to the storage contract
* cannot bind more than 300 IR to 1 IRS
* @param _identityRegistry The identity registry address to add.
*/
function bindIdentityRegistry(address _identityRegistry) external;
/**
* @notice Removes an identity registry from being agent of the Identity Registry Storage Contract.
* This function can only be called by the wallet set as owner of the smart contract
* This function removes the identity registry from the list of identityRegistries linked to the storage contract
* @param _identityRegistry The identity registry address to remove.
*/
function unbindIdentityRegistry(address _identityRegistry) external;
/**
* @dev Returns the identity registries linked to the storage contract
*/
function linkedIdentityRegistries() external view returns (address[] memory);
/**
* @dev Returns the onchainID of an investor.
* @param _userAddress The wallet of the investor
*/
function storedIdentity(address _userAddress) external view returns (IIdentity);
/**
* @dev Returns the country code of an investor.
* @param _userAddress The wallet of the investor
*/
function storedInvestorCountry(address _userAddress) external view returns (uint16);
}
IClaimIssuer.sol 59 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
import "./IIdentity.sol";
interface IClaimIssuer is IIdentity {
/**
* @dev Emitted when a claim is revoked.
*
* Specification: MUST be triggered when revoking a claim.
*/
event ClaimRevoked(bytes indexed signature);
/**
* @dev Revoke a claim previously issued, the claim is no longer considered as valid after revocation.
* @notice will fetch the claim from the identity contract (unsafe).
* @param _claimId the id of the claim
* @param _identity the address of the identity contract
* @return isRevoked true when the claim is revoked
*/
function revokeClaim(bytes32 _claimId, address _identity) external returns(bool);
/**
* @dev Revoke a claim previously issued, the claim is no longer considered as valid after revocation.
* @param signature the signature of the claim
*/
function revokeClaimBySignature(bytes calldata signature) external;
/**
* @dev Returns revocation status of a claim.
* @param _sig the signature of the claim
* @return isRevoked true if the claim is revoked and false otherwise
*/
function isClaimRevoked(bytes calldata _sig) external view returns (bool);
/**
* @dev Checks if a claim is valid.
* @param _identity the identity contract related to the claim
* @param claimTopic the claim topic of the claim
* @param sig the signature of the claim
* @param data the data field of the claim
* @return claimValid true if the claim is valid, false otherwise
*/
function isClaimValid(
IIdentity _identity,
uint256 claimTopic,
bytes calldata sig,
bytes calldata data)
external view returns (bool);
/**
* @dev returns the address that signed the given data
* @param sig the signature of the data
* @param dataHash the data that was signed
* returns the address that signed dataHash and created the signature sig
*/
function getRecoveredAddress(bytes calldata sig, bytes32 dataHash) external pure returns (address);
}
IIdentity.sol 8 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
import "./IERC734.sol";
import "./IERC735.sol";
// solhint-disable-next-line no-empty-blocks
interface IIdentity is IERC734, IERC735 {}
draft-IERC1822.sol 20 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}
ERC1967Upgrade.sol 185 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*
* @custom:oz-upgrades-unsafe-allow delegatecall
*/
abstract contract ERC1967Upgrade {
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Emitted when the beacon is upgraded.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
Address.isContract(IBeacon(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(
address newBeacon,
bytes memory data,
bool forceCall
) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
}
}
}
ContextUpgradeable.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
Initializable.sol 166 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}
IModularCompliance.sol 230 lines
// SPDX-License-Identifier: GPL-3.0
//
// :+#####%%%%%%%%%%%%%%+
// .-*@@@%+.:+%@@@@@%%#***%@@%=
// :=*%@@@#=. :#@@% *@@@%=
// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
// @@@@@@+. +@@*. .+@@@@@%=.
// -@@@@@= =@@%: -#@@@@%+.
// +@@@@@. =@@@= .+@@@@@*:
// #@@@@#:%@@#. :*@@@@#-
// @@@@@%@@@= :#@@@@+.
// :@@@@@@@#.:#@@@%-
// +@@@@@@-.*@@@*:
// #@@@@#.=@@@+.
// @@@@+-%@%=
// :@@@#%@%=
// +@@@@%-
// :#%%=
//
/**
* NOTICE
*
* The T-REX software is licensed under a proprietary license or the GPL v.3.
* If you choose to receive it under the GPL v.3 license, the following applies:
* T-REX is a suite of smart contracts implementing the ERC-3643 standard and
* developed by Tokeny to manage and transfer financial assets on EVM blockchains
*
* Copyright (C) 2023, Tokeny sàrl.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pragma solidity 0.8.17;
interface IModularCompliance {
/// events
/**
* @dev Event emitted for each executed interaction with a module contract.
* For gas efficiency, only the interaction calldata selector (first 4
* bytes) is included in the event. For interactions without calldata or
* whose calldata is shorter than 4 bytes, the selector will be `0`.
*/
event ModuleInteraction(address indexed target, bytes4 selector);
/**
* this event is emitted when a token has been bound to the compliance contract
* the event is emitted by the bindToken function
* `_token` is the address of the token to bind
*/
event TokenBound(address _token);
/**
* this event is emitted when a token has been unbound from the compliance contract
* the event is emitted by the unbindToken function
* `_token` is the address of the token to unbind
*/
event TokenUnbound(address _token);
/**
* this event is emitted when a module has been added to the list of modules bound to the compliance contract
* the event is emitted by the addModule function
* `_module` is the address of the compliance module
*/
event ModuleAdded(address indexed _module);
/**
* this event is emitted when a module has been removed from the list of modules bound to the compliance contract
* the event is emitted by the removeModule function
* `_module` is the address of the compliance module
*/
event ModuleRemoved(address indexed _module);
/// functions
/**
* @dev binds a token to the compliance contract
* @param _token address of the token to bind
* This function can be called ONLY by the owner of the compliance contract
* Emits a TokenBound event
*/
function bindToken(address _token) external;
/**
* @dev unbinds a token from the compliance contract
* @param _token address of the token to unbind
* This function can be called ONLY by the owner of the compliance contract
* Emits a TokenUnbound event
*/
function unbindToken(address _token) external;
/**
* @dev adds a module to the list of compliance modules
* @param _module address of the module to add
* there cannot be more than 25 modules bound to the modular compliance for gas cost reasons
* This function can be called ONLY by the owner of the compliance contract
* Emits a ModuleAdded event
*/
function addModule(address _module) external;
/**
* @dev removes a module from the list of compliance modules
* @param _module address of the module to remove
* This function can be called ONLY by the owner of the compliance contract
* Emits a ModuleRemoved event
*/
function removeModule(address _module) external;
/**
* @dev calls any function on bound modules
* can be called only on bound modules
* @param callData the bytecode for interaction with the module, abi encoded
* @param _module The address of the module
* This function can be called only by the modular compliance owner
* emits a `ModuleInteraction` event
*/
function callModuleFunction(bytes calldata callData, address _module) external;
/**
* @dev function called whenever tokens are transferred
* from one wallet to another
* this function can update state variables in the modules bound to the compliance
* these state variables being used by the module checks to decide if a transfer
* is compliant or not depending on the values stored in these state variables and on
* the parameters of the modules
* This function can be called ONLY by the token contract bound to the compliance
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The amount of tokens involved in the transfer
* This function calls moduleTransferAction() on each module bound to the compliance contract
*/
function transferred(
address _from,
address _to,
uint256 _amount
) external;
/**
* @dev function called whenever tokens are created on a wallet
* this function can update state variables in the modules bound to the compliance
* these state variables being used by the module checks to decide if a transfer
* is compliant or not depending on the values stored in these state variables and on
* the parameters of the modules
* This function can be called ONLY by the token contract bound to the compliance
* @param _to The address of the receiver
* @param _amount The amount of tokens involved in the minting
* This function calls moduleMintAction() on each module bound to the compliance contract
*/
function created(address _to, uint256 _amount) external;
/**
* @dev function called whenever tokens are destroyed from a wallet
* this function can update state variables in the modules bound to the compliance
* these state variables being used by the module checks to decide if a transfer
* is compliant or not depending on the values stored in these state variables and on
* the parameters of the modules
* This function can be called ONLY by the token contract bound to the compliance
* @param _from The address on which tokens are burnt
* @param _amount The amount of tokens involved in the burn
* This function calls moduleBurnAction() on each module bound to the compliance contract
*/
function destroyed(address _from, uint256 _amount) external;
/**
* @dev checks that the transfer is compliant.
* default compliance always returns true
* READ ONLY FUNCTION, this function cannot be used to increment
* counters, emit events, ...
* @param _from The address of the sender
* @param _to The address of the receiver
* @param _amount The amount of tokens involved in the transfer
* This function will call moduleCheck() on every module bound to the compliance
* If each of the module checks return TRUE, this function will return TRUE as well
* returns FALSE otherwise
*/
function canTransfer(
address _from,
address _to,
uint256 _amount
) external view returns (bool);
/**
* @dev getter for the modules bound to the compliance contract
* returns address array of module contracts bound to the compliance
*/
function getModules() external view returns (address[] memory);
/**
* @dev getter for the address of the token bound
* returns the address of the token
*/
function getTokenBound() external view returns (address);
/**
* @dev checks if a module is bound to the compliance contract
* returns true if module is bound, false otherwise
*/
function isModuleBound(address _module) external view returns (bool);
}
IERC20.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
EnumerableSet.sol 378 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}
ProxyBeacon.sol 41 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
/**
* @notice The PoolContractsRegistry module
*
* This is a utility lightweighted ProxyBeacon contract this is used as a beacon that BeaconProxies point to.
*/
contract ProxyBeacon is IBeacon {
using Address for address;
address private immutable _OWNER;
address private _implementation;
event Upgraded(address implementation);
modifier onlyOwner() {
require(_OWNER == msg.sender, "ProxyBeacon: not an owner");
_;
}
constructor() {
_OWNER = msg.sender;
}
function upgrade(address newImplementation_) external onlyOwner {
require(newImplementation_.isContract(), "ProxyBeacon: not a contract");
_implementation = newImplementation_;
emit Upgraded(newImplementation_);
}
function implementation() external view override returns (address) {
return _implementation;
}
}
IERC734.sol 111 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
/**
* @dev interface of the ERC734 (Key Holder) standard as defined in the EIP.
*/
interface IERC734 {
/**
* @dev Emitted when an execution request was approved.
*
* Specification: MUST be triggered when approve was successfully called.
*/
event Approved(uint256 indexed executionId, bool approved);
/**
* @dev Emitted when an execute operation was approved and successfully performed.
*
* Specification: MUST be triggered when approve was called and the execution was successfully approved.
*/
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
/**
* @dev Emitted when an execution request was performed via `execute`.
*
* Specification: MUST be triggered when execute was successfully called.
*/
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
/**
* @dev Emitted when an execute operation was called and failed
*
* Specification: MUST be triggered when execute call failed
*/
event ExecutionFailed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
/**
* @dev Emitted when a key was added to the Identity.
*
* Specification: MUST be triggered when addKey was successfully called.
*/
event KeyAdded(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
/**
* @dev Emitted when a key was removed from the Identity.
*
* Specification: MUST be triggered when removeKey was successfully called.
*/
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
/**
* @dev Adds a _key to the identity. The _purpose specifies the purpose of the key.
*
* Triggers Event: `KeyAdded`
*
* Specification: MUST only be done by keys of purpose 1, or the identity
* itself. If it's the identity itself, the approval process will determine its approval.
*/
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) external returns (bool success);
/**
* @dev Approves an execution.
*
* Triggers Event: `Approved`
* Triggers on execution successful Event: `Executed`
* Triggers on execution failure Event: `ExecutionFailed`
*/
function approve(uint256 _id, bool _approve) external returns (bool success);
/**
* @dev Removes _purpose for _key from the identity.
*
* Triggers Event: `KeyRemoved`
*
* Specification: MUST only be done by keys of purpose 1, or the identity itself.
* If it's the identity itself, the approval process will determine its approval.
*/
function removeKey(bytes32 _key, uint256 _purpose) external returns (bool success);
/**
* @dev Passes an execution instruction to an ERC734 identity.
* How the execution is handled is up to the identity implementation:
* An execution COULD be requested and require `approve` to be called with one or more keys of purpose 1 or 2 to
* approve this execution.
* Execute COULD be used as the only accessor for `addKey` and `removeKey`.
*
* Triggers Event: ExecutionRequested
* Triggers on direct execution Event: Executed
*/
function execute(address _to, uint256 _value, bytes calldata _data) external payable returns (uint256 executionId);
/**
* @dev Returns the full key data, if present in the identity.
*/
function getKey(bytes32 _key) external view returns (uint256[] memory purposes, uint256 keyType, bytes32 key);
/**
* @dev Returns the list of purposes associated with a key.
*/
function getKeyPurposes(bytes32 _key) external view returns(uint256[] memory _purposes);
/**
* @dev Returns an array of public key bytes32 held by this identity.
*/
function getKeysByPurpose(uint256 _purpose) external view returns (bytes32[] memory keys);
/**
* @dev Returns TRUE if a key is present and has the given purpose. If the key is not present it returns FALSE.
*/
function keyHasPurpose(bytes32 _key, uint256 _purpose) external view returns (bool exists);
}
IERC735.sol 98 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
/**
* @dev interface of the ERC735 (Claim Holder) standard as defined in the EIP.
*/
interface IERC735 {
/**
* @dev Emitted when a claim was added.
*
* Specification: MUST be triggered when a claim was successfully added.
*/
event ClaimAdded(
bytes32 indexed claimId,
uint256 indexed topic,
uint256 scheme,
address indexed issuer,
bytes signature,
bytes data,
string uri);
/**
* @dev Emitted when a claim was removed.
*
* Specification: MUST be triggered when removeClaim was successfully called.
*/
event ClaimRemoved(
bytes32 indexed claimId,
uint256 indexed topic,
uint256 scheme,
address indexed issuer,
bytes signature,
bytes data,
string uri);
/**
* @dev Emitted when a claim was changed.
*
* Specification: MUST be triggered when addClaim was successfully called on an existing claimId.
*/
event ClaimChanged(
bytes32 indexed claimId,
uint256 indexed topic,
uint256 scheme,
address indexed issuer,
bytes signature,
bytes data,
string uri);
/**
* @dev Add or update a claim.
*
* Triggers Event: `ClaimAdded`, `ClaimChanged`
*
* Specification: Add or update a claim from an issuer.
*
* _signature is a signed message of the following structure:
* `keccak256(abi.encode(address identityHolder_address, uint256 topic, bytes data))`.
* Claim IDs are generated using `keccak256(abi.encode(address issuer_address + uint256 topic))`.
*/
function addClaim(
uint256 _topic,
uint256 _scheme,
address issuer,
bytes calldata _signature,
bytes calldata _data,
string calldata _uri)
external returns (bytes32 claimRequestId);
/**
* @dev Removes a claim.
*
* Triggers Event: `ClaimRemoved`
*
* Claim IDs are generated using `keccak256(abi.encode(address issuer_address, uint256 topic))`.
*/
function removeClaim(bytes32 _claimId) external returns (bool success);
/**
* @dev Get a claim by its ID.
*
* Claim IDs are generated using `keccak256(abi.encode(address issuer_address, uint256 topic))`.
*/
function getClaim(bytes32 _claimId)
external view returns(
uint256 topic,
uint256 scheme,
address issuer,
bytes memory signature,
bytes memory data,
string memory uri);
/**
* @dev Returns an array of claim IDs by topic.
*/
function getClaimIdsByTopic(uint256 _topic) external view returns(bytes32[] memory claimIds);
}
IBeacon.sol 16 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
StorageSlot.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}
AddressUpgradeable.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Read Contract
getFundDepositToken 0x2b0fb787 → address
getFundDepositTokenKey 0xe45d3d28 → bytes32
isAgent 0x1ffbb064 → bool
owner 0x8da5cb5b → address
paused 0x5c975abb → bool
proxiableUUID 0x52d1902d → bytes32
Write Contract 16 functions
These functions modify contract state and require a wallet transaction to execute.
addAgent 0x84e79842
address _agent
burnToken 0x3416794d
address tokenAddr_
address userAddress_
uint256 amount_
init 0x49012589
tuple[] initDataArr_
address identityRegistry_
address adminIdentity_
address permissionsManager_
address complianceFactory_
address tokensFactory_
mintDigitalSecurity 0xd77f51e2
tuple initData_
tuple updateData_
uint256 amount_
address userAddress_
returns: address
mintFundDepositForTreasury 0x105ec42a
tuple depositData_
address treasuryAddress_
uint256 amount_
returns: address
mintOnChainAsset 0x9faec7ae
tuple specData_
tuple issuanceData_
tuple updateData_
address custodianAddress_
returns: address
mintTokenForUser 0xd7db6cba
address tokenAddr_
address userAddress_
uint256 amount_
pause 0x8456cb59
No parameters
removeAgent 0x97a6278e
address _agent
renounceOwnership 0x715018a6
No parameters
setTokensInitData 0x23237dab
tuple[] initDataArr_
transferOwnership 0xf2fde38b
address newOwner
transferToken 0x2c54de4f
address tokenAddr_
address userAddressFrom_
address userAddressTo_
uint256 amount_
unpause 0x3f4ba83a
No parameters
upgradeTo 0x3659cfe6
address newImplementation
upgradeToAndCall 0x4f1ef286
address newImplementation
bytes data
Recent Transactions
No transactions found for this address