├── README.md ├── TokenConverter.abi └── TokenConverter.sol /README.md: -------------------------------------------------------------------------------- 1 | # Ethereum Token Converter 2 | 3 | This service is created to introduce "cross-standard" interoperability of tokens on Ethereum and EVM-compatible chains. 4 | 5 | The most used Ethereum fungible token standard is [ERC-20](https://eips.ethereum.org/EIPS/eip-20) and this standard is quite old. Therefore it is necessary to introduce a clear procedure of "standard upgrade" without requiring redeploying of existing token contracts. The Token Converter smart-contract can be exactly the tool that ensures smooth transition from the old standard to a newer one. 6 | 7 | This particular implementation converts [ERC-20](https://eips.ethereum.org/EIPS/eip-20) tokens to [ERC-223](https://eips.ethereum.org/EIPS/eip-223) tokens. ERC-223 tokens can be converted back to the ERC-20 origin anytime. 8 | 9 | # Deployment 10 | 11 | Converter v4 (CLO mainnet): https://explorer.callisto.network/address/0xf0ddb84596C9B52981C2bFf35c8B21d2b8FEd64c/transactions 12 | 13 | Ethereum Mainnet v4: https://etherscan.io/address/0x1e9d6cba29e4aa4a9e2587b19d3f0e68de9b6552 14 | 15 | # Creation codes for wrapper tokens (required by DEXes) 16 | 17 | Compiled with v0.8.19+commit.7dd6d404 5000 optimization runs as deployed on ETH mainnet at [0xe7E969012557f25bECddB717A3aa2f4789ba9f9a](https://etherscan.io/address/0xe7E969012557f25bECddB717A3aa2f4789ba9f9a#code) 18 | 19 | ERC-20: 20 | 21 | ``` 22 | 0x6080604052600180546001600160a01b03199081167301000b5fe61411c466b70631d7ff070187179bbf17909155600280549091163317905534801561004457600080fd5b506100556301ffc9a760e01b61005a565b6100dd565b6001600160e01b031980821690036100b85760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640160405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b61101e806100ec6000396000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806340c10f19116100b257806395d89b4111610081578063a9059cbb11610066578063a9059cbb14610298578063d3d2bfda146102ab578063dd62ed3e146102be57600080fd5b806395d89b411461027d5780639dc29fac1461028557600080fd5b806340c10f191461021d57806370a08231146102305780638cd4426d14610259578063938b5f321461026c57600080fd5b806318160ddd1161010957806323b872dd116100ee57806323b872dd146101db5780632801617e146101ee578063313ce5671461020357600080fd5b806318160ddd146101b657806319d16c49146101c857600080fd5b806301ffc9a71461013b57806302d05d3f1461016357806306fdde031461018e578063095ea7b3146101a3575b600080fd5b61014e610149366004610ca5565b6102f7565b60405190151581526020015b60405180910390f35b600254610176906001600160a01b031681565b6040516001600160a01b03909116815260200161015a565b6101966103cc565b60405161015a9190610d12565b61014e6101b1366004610d61565b61045c565b6005545b60405190815260200161015a565b600154610176906001600160a01b031681565b61014e6101e9366004610d8b565b610538565b6102016101fc366004610dc7565b6106b0565b005b61020b610701565b60405160ff909116815260200161015a565b61020161022b366004610d61565b610788565b6101ba61023e366004610dc7565b6001600160a01b031660009081526006602052604090205490565b610201610267366004610d61565b6108d3565b6003546001600160a01b0316610176565b6101966108ef565b610201610293366004610d61565b61099e565b61014e6102a6366004610d61565b610aa9565b600354610176906001600160a01b031681565b6101ba6102cc366004610de2565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f36372b0700000000000000000000000000000000000000000000000000000000148061038a57507fffffffff0000000000000000000000000000000000000000000000000000000082167f809d3ae700000000000000000000000000000000000000000000000000000000145b806103c657507fffffffff00000000000000000000000000000000000000000000000000000000821660009081526020819052604090205460ff165b92915050565b600354604080517f06fdde0300000000000000000000000000000000000000000000000000000000815290516060926001600160a01b0316916306fdde039160048083019260009291908290030181865afa15801561042f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526104579190810190610e44565b905090565b60006001600160a01b0383166104d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f45524332303a205370656e646572206572726f722e000000000000000000000060448201526064015b60405180910390fd5b3360008181526004602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a350600192915050565b6001600160a01b03831660009081526004602090815260408083203384529091528120548211156105c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f45524332303a20496e73756666696369656e7420616c6c6f77616e63652e000060448201526064016104ca565b6001600160a01b038416600090815260066020526040812080548492906105ed908490610f20565b90915550506001600160a01b038416600090815260046020908152604080832033845290915281208054849290610625908490610f20565b90915550506001600160a01b03831660009081526006602052604081208054849290610652908490610f33565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161069e91815260200190565b60405180910390a35060019392505050565b6002546001600160a01b031633146106c757600080fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600354604080517f313ce56700000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa158015610764573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104579190610f46565b6002546001600160a01b03163314610848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f5772617070657220546f6b656e3a204f6e6c79207468652063726561746f722060448201527f636f6e74726163742063616e206d696e74207772617070657220746f6b656e7360648201527f2e00000000000000000000000000000000000000000000000000000000000000608482015260a4016104ca565b6001600160a01b03821660009081526006602052604081208054839290610870908490610f33565b9250508190555080600560008282546108899190610f33565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6001546108eb9083906001600160a01b031683610b42565b5050565b600354604080517f95d89b4100000000000000000000000000000000000000000000000000000000815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015610952573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261097a9190810190610e44565b60405160200161098a9190610f69565b604051602081830303815290604052905090565b6002546001600160a01b03163314610a5f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526044602482018190527f5772617070657220546f6b656e3a204f6e6c79207468652063726561746f7220908201527f636f6e74726163742063616e2064657374726f79207772617070657220746f6b60648201527f656e732e00000000000000000000000000000000000000000000000000000000608482015260a4016104ca565b6001600160a01b03821660009081526006602052604081208054839290610a87908490610f20565b925050819055508060056000828254610aa09190610f20565b90915550505050565b33600090815260066020526040812054610ac4908390610f20565b33600090815260066020526040808220929092556001600160a01b03851681522054610af1908390610f33565b6001600160a01b0384166000818152600660205260409081902092909255905133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906105279086815260200190565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691610bcc9190610faa565b6000604051808303816000865af19150503d8060008114610c09576040519150601f19603f3d011682016040523d82523d6000602084013e610c0e565b606091505b5091509150818015610c38575080511580610c38575080806020019051810190610c389190610fc6565b610c9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c45440060448201526064016104ca565b5050505050565b600060208284031215610cb757600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610ce757600080fd5b9392505050565b60005b83811015610d09578181015183820152602001610cf1565b50506000910152565b6020815260008251806020840152610d31816040850160208701610cee565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114610d5c57600080fd5b919050565b60008060408385031215610d7457600080fd5b610d7d83610d45565b946020939093013593505050565b600080600060608486031215610da057600080fd5b610da984610d45565b9250610db760208501610d45565b9150604084013590509250925092565b600060208284031215610dd957600080fd5b610ce782610d45565b60008060408385031215610df557600080fd5b610dfe83610d45565b9150610e0c60208401610d45565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215610e5657600080fd5b815167ffffffffffffffff80821115610e6e57600080fd5b818401915084601f830112610e8257600080fd5b815181811115610e9457610e94610e15565b604051601f8201601f19908116603f01168101908382118183101715610ebc57610ebc610e15565b81604052828152876020848701011115610ed557600080fd5b610ee6836020830160208801610cee565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156103c6576103c6610ef1565b808201808211156103c6576103c6610ef1565b600060208284031215610f5857600080fd5b815160ff81168114610ce757600080fd5b60008251610f7b818460208701610cee565b7f3230000000000000000000000000000000000000000000000000000000000000920191825250600201919050565b60008251610fbc818460208701610cee565b9190910192915050565b600060208284031215610fd857600080fd5b81518015158114610ce757600080fdfea2646970667358221220e97d1031a2ac6100b71c279bbb8287919b290b83e83d32e852bee9845fc0aeb064736f6c63430008130033 23 | ``` 24 | 25 | 26 | ERC-223: 27 | 28 | ``` 29 | 0x6080604052600180546001600160a01b03199081167301000b5fe61411c466b70631d7ff070187179bbf17909155600280549091163317905534801561004457600080fd5b506100556301ffc9a760e01b61005a565b6100dd565b6001600160e01b031980821690036100b85760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640160405180910390fd5b6001600160e01b0319166000908152602081905260409020805460ff19166001179055565b61153a806100ec6000396000f3fe6080604052600436106101445760003560e01c806340c10f19116100c0578063938b5f3211610074578063a9059cbb11610059578063a9059cbb14610385578063be45fd62146103a5578063dd62ed3e146103b857600080fd5b8063938b5f321461035257806395d89b411461037057600080fd5b80635a3b7e42116100a55780635a3b7e42146102e057806370a08231146102fc5780638cd4426d1461033257600080fd5b806340c10f19146102a057806342966c68146102c057600080fd5b806318160ddd1161011757806323b872dd116100fc57806323b872dd146102375780632801617e14610257578063313ce5671461027957600080fd5b806318160ddd146101f857806319d16c491461021757600080fd5b806301ffc9a71461014957806302d05d3f1461017e57806306fdde03146101b6578063095ea7b3146101d8575b600080fd5b34801561015557600080fd5b50610169610164366004611072565b6103fe565b60405190151581526020015b60405180910390f35b34801561018a57600080fd5b5060025461019e906001600160a01b031681565b6040516001600160a01b039091168152602001610175565b3480156101c257600080fd5b506101cb6104d3565b60405161017591906110e6565b3480156101e457600080fd5b506101696101f3366004611115565b610563565b34801561020457600080fd5b506005545b604051908152602001610175565b34801561022357600080fd5b5060015461019e906001600160a01b031681565b34801561024357600080fd5b5061016961025236600461113f565b61063e565b34801561026357600080fd5b5061027761027236600461117b565b6107b6565b005b34801561028557600080fd5b5061028e610807565b60405160ff9091168152602001610175565b3480156102ac57600080fd5b506102776102bb366004611115565b61088e565b3480156102cc57600080fd5b506102776102db366004611196565b6109d9565b3480156102ec57600080fd5b5060405160df8152602001610175565b34801561030857600080fd5b5061020961031736600461117b565b6001600160a01b031660009081526006602052604090205490565b34801561033e57600080fd5b5061027761034d366004611115565b610ada565b34801561035e57600080fd5b506003546001600160a01b031661019e565b34801561037c57600080fd5b506101cb610af6565b34801561039157600080fd5b506101696103a0366004611115565b610ba5565b6101696103b33660046111af565b610cf7565b3480156103c457600080fd5b506102096103d3366004611236565b6001600160a01b03918216600090815260046020908152604080832093909416825291909152205490565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f3ed8c78500000000000000000000000000000000000000000000000000000000148061049157507fffffffff0000000000000000000000000000000000000000000000000000000082167fddef4e1000000000000000000000000000000000000000000000000000000000145b806104cd57507fffffffff00000000000000000000000000000000000000000000000000000000821660009081526020819052604090205460ff165b92915050565b600354604080517f06fdde0300000000000000000000000000000000000000000000000000000000815290516060926001600160a01b0316916306fdde039160048083019260009291908290030181865afa158015610536573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261055e9190810190611298565b905090565b60006001600160a01b0383166105da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4552433232333a205370656e646572206572726f722e0000000000000000000060448201526064015b60405180910390fd5b3360008181526004602090815260408083206001600160a01b03881680855290835292819020869055518581529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350600192915050565b6001600160a01b03831660009081526004602090815260408083203384529091528120548211156106cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4552433232333a20496e73756666696369656e7420616c6c6f77616e63652e0060448201526064016105d1565b6001600160a01b038416600090815260066020526040812080548492906106f3908490611374565b90915550506001600160a01b03841660009081526004602090815260408083203384529091528120805484929061072b908490611374565b90915550506001600160a01b03831660009081526006602052604081208054849290610758908490611387565b92505081905550826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516107a491815260200190565b60405180910390a35060019392505050565b6002546001600160a01b031633146107cd57600080fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b600354604080517f313ce56700000000000000000000000000000000000000000000000000000000815290516000926001600160a01b03169163313ce5679160048083019260209291908290030181865afa15801561086a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055e919061139a565b6002546001600160a01b0316331461094e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152604160248201527f5772617070657220546f6b656e3a204f6e6c79207468652063726561746f722060448201527f636f6e74726163742063616e206d696e74207772617070657220746f6b656e7360648201527f2e00000000000000000000000000000000000000000000000000000000000000608482015260a4016105d1565b6001600160a01b03821660009081526006602052604081208054839290610976908490611387565b92505081905550806005600082825461098f9190611387565b90915550506040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b6002546001600160a01b03163314610a9a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526044602482018190527f5772617070657220546f6b656e3a204f6e6c79207468652063726561746f7220908201527f636f6e74726163742063616e2064657374726f79207772617070657220746f6b60648201527f656e732e00000000000000000000000000000000000000000000000000000000608482015260a4016105d1565b3360009081526006602052604081208054839290610ab9908490611374565b925050819055508060056000828254610ad29190611374565b909155505050565b600154610af29083906001600160a01b031683610ede565b5050565b600354604080517f95d89b4100000000000000000000000000000000000000000000000000000000815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015610b59573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b819190810190611298565b604051602001610b9191906113bd565b604051602081830303815290604052905090565b60408051808201825260048152600060208083018290523382526006905291822054610bd2908490611374565b33600090815260066020526040808220929092556001600160a01b03861681522054610bff908490611387565b6001600160a01b038516600090815260066020526040902055833b15610cad576040517f8943ec020000000000000000000000000000000000000000000000000000000081526001600160a01b03851690638943ec0290610c68903390879086906004016113fe565b6020604051808303816000875af1158015610c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cab919061142f565b505b6040518381526001600160a01b0385169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35060019392505050565b33600090815260066020526040812054610d12908590611374565b33600090815260066020526040808220929092556001600160a01b03871681522054610d3f908590611387565b6001600160a01b0386166000908152600660205260409020553415610dc357600080866001600160a01b03163460405160006040518083038185875af1925050503d8060008114610dac576040519150601f19603f3d011682016040523d82523d6000602084013e610db1565b606091505b509150915081610dc057600080fd5b50505b843b15610e5a576040517f8943ec020000000000000000000000000000000000000000000000000000000081526001600160a01b03861690638943ec0290610e15903390889088908890600401611477565b6020604051808303816000875af1158015610e34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e58919061142f565b505b6040518481526001600160a01b0386169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a37f3ba9136826ac751de05d770d8d34fa4440ada49a5fb0e9aa1678aece66dad9768383604051610ecb9291906114aa565b60405180910390a1506001949350505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691610f6891906114c6565b6000604051808303816000865af19150503d8060008114610fa5576040519150601f19603f3d011682016040523d82523d6000602084013e610faa565b606091505b5091509150818015610fd4575080511580610fd4575080806020019051810190610fd491906114e2565b61103a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c45440060448201526064016105d1565b5050505050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461106f57600080fd5b50565b60006020828403121561108457600080fd5b813561108f81611041565b9392505050565b60005b838110156110b1578181015183820152602001611099565b50506000910152565b600081518084526110d2816020860160208601611096565b601f01601f19169290920160200192915050565b60208152600061108f60208301846110ba565b80356001600160a01b038116811461111057600080fd5b919050565b6000806040838503121561112857600080fd5b611131836110f9565b946020939093013593505050565b60008060006060848603121561115457600080fd5b61115d846110f9565b925061116b602085016110f9565b9150604084013590509250925092565b60006020828403121561118d57600080fd5b61108f826110f9565b6000602082840312156111a857600080fd5b5035919050565b600080600080606085870312156111c557600080fd5b6111ce856110f9565b935060208501359250604085013567ffffffffffffffff808211156111f257600080fd5b818701915087601f83011261120657600080fd5b81358181111561121557600080fd5b88602082850101111561122757600080fd5b95989497505060200194505050565b6000806040838503121561124957600080fd5b611252836110f9565b9150611260602084016110f9565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156112aa57600080fd5b815167ffffffffffffffff808211156112c257600080fd5b818401915084601f8301126112d657600080fd5b8151818111156112e8576112e8611269565b604051601f8201601f19908116603f0116810190838211818310171561131057611310611269565b8160405282815287602084870101111561132957600080fd5b61133a836020830160208801611096565b979650505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156104cd576104cd611345565b808201808211156104cd576104cd611345565b6000602082840312156113ac57600080fd5b815160ff8116811461108f57600080fd5b600082516113cf818460208701611096565b7f3232330000000000000000000000000000000000000000000000000000000000920191825250600301919050565b6001600160a01b038416815282602082015260606040820152600061142660608301846110ba565b95945050505050565b60006020828403121561144157600080fd5b815161108f81611041565b818352818160208501375060006020828401015260006020601f19601f840116840101905092915050565b6001600160a01b03851681528360208201526060604082015260006114a060608301848661144c565b9695505050505050565b6020815260006114be60208301848661144c565b949350505050565b600082516114d8818460208701611096565b9190910192915050565b6000602082840312156114f457600080fd5b8151801515811461108f57600080fdfea2646970667358221220792f0f0603c575622971125598346cae31eefaa8958ce1751c1206676bb1d60d64736f6c63430008130033 30 | ``` 31 | -------------------------------------------------------------------------------- /TokenConverter.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "_token", 7 | "type": "address" 8 | } 9 | ], 10 | "name": "createERC20Wrapper", 11 | "outputs": [ 12 | { 13 | "internalType": "address", 14 | "name": "", 15 | "type": "address" 16 | } 17 | ], 18 | "stateMutability": "nonpayable", 19 | "type": "function" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "internalType": "address", 25 | "name": "_token", 26 | "type": "address" 27 | } 28 | ], 29 | "name": "createERC223Wrapper", 30 | "outputs": [ 31 | { 32 | "internalType": "address", 33 | "name": "", 34 | "type": "address" 35 | } 36 | ], 37 | "stateMutability": "nonpayable", 38 | "type": "function" 39 | }, 40 | { 41 | "inputs": [ 42 | { 43 | "internalType": "address", 44 | "name": "_token", 45 | "type": "address" 46 | }, 47 | { 48 | "internalType": "uint256", 49 | "name": "_amount", 50 | "type": "uint256" 51 | } 52 | ], 53 | "name": "depositERC20", 54 | "outputs": [ 55 | { 56 | "internalType": "bool", 57 | "name": "", 58 | "type": "bool" 59 | } 60 | ], 61 | "stateMutability": "nonpayable", 62 | "type": "function" 63 | }, 64 | { 65 | "inputs": [ 66 | { 67 | "internalType": "address", 68 | "name": "", 69 | "type": "address" 70 | } 71 | ], 72 | "name": "erc20Origins", 73 | "outputs": [ 74 | { 75 | "internalType": "address", 76 | "name": "", 77 | "type": "address" 78 | } 79 | ], 80 | "stateMutability": "view", 81 | "type": "function" 82 | }, 83 | { 84 | "inputs": [ 85 | { 86 | "internalType": "address", 87 | "name": "", 88 | "type": "address" 89 | } 90 | ], 91 | "name": "erc20Supply", 92 | "outputs": [ 93 | { 94 | "internalType": "uint256", 95 | "name": "", 96 | "type": "uint256" 97 | } 98 | ], 99 | "stateMutability": "view", 100 | "type": "function" 101 | }, 102 | { 103 | "inputs": [ 104 | { 105 | "internalType": "address", 106 | "name": "", 107 | "type": "address" 108 | } 109 | ], 110 | "name": "erc20Wrappers", 111 | "outputs": [ 112 | { 113 | "internalType": "contract ERC20WrapperToken", 114 | "name": "", 115 | "type": "address" 116 | } 117 | ], 118 | "stateMutability": "view", 119 | "type": "function" 120 | }, 121 | { 122 | "inputs": [ 123 | { 124 | "internalType": "address", 125 | "name": "", 126 | "type": "address" 127 | } 128 | ], 129 | "name": "erc223Origins", 130 | "outputs": [ 131 | { 132 | "internalType": "address", 133 | "name": "", 134 | "type": "address" 135 | } 136 | ], 137 | "stateMutability": "view", 138 | "type": "function" 139 | }, 140 | { 141 | "inputs": [ 142 | { 143 | "internalType": "address", 144 | "name": "", 145 | "type": "address" 146 | } 147 | ], 148 | "name": "erc223Wrappers", 149 | "outputs": [ 150 | { 151 | "internalType": "contract ERC223WrapperToken", 152 | "name": "", 153 | "type": "address" 154 | } 155 | ], 156 | "stateMutability": "view", 157 | "type": "function" 158 | }, 159 | { 160 | "inputs": [ 161 | { 162 | "internalType": "address", 163 | "name": "_token", 164 | "type": "address" 165 | } 166 | ], 167 | "name": "getOriginFor", 168 | "outputs": [ 169 | { 170 | "internalType": "address", 171 | "name": "", 172 | "type": "address" 173 | }, 174 | { 175 | "internalType": "string", 176 | "name": "", 177 | "type": "string" 178 | } 179 | ], 180 | "stateMutability": "view", 181 | "type": "function" 182 | }, 183 | { 184 | "inputs": [ 185 | { 186 | "internalType": "address", 187 | "name": "_token", 188 | "type": "address" 189 | } 190 | ], 191 | "name": "getWrapperFor", 192 | "outputs": [ 193 | { 194 | "internalType": "address", 195 | "name": "", 196 | "type": "address" 197 | }, 198 | { 199 | "internalType": "string", 200 | "name": "", 201 | "type": "string" 202 | } 203 | ], 204 | "stateMutability": "view", 205 | "type": "function" 206 | }, 207 | { 208 | "inputs": [ 209 | { 210 | "internalType": "address", 211 | "name": "_token", 212 | "type": "address" 213 | } 214 | ], 215 | "name": "isWrapper", 216 | "outputs": [ 217 | { 218 | "internalType": "bool", 219 | "name": "", 220 | "type": "bool" 221 | } 222 | ], 223 | "stateMutability": "view", 224 | "type": "function" 225 | }, 226 | { 227 | "inputs": [], 228 | "name": "ownerMultisig", 229 | "outputs": [ 230 | { 231 | "internalType": "address", 232 | "name": "", 233 | "type": "address" 234 | } 235 | ], 236 | "stateMutability": "view", 237 | "type": "function" 238 | }, 239 | { 240 | "inputs": [ 241 | { 242 | "internalType": "address", 243 | "name": "_token", 244 | "type": "address" 245 | } 246 | ], 247 | "name": "rescueERC20", 248 | "outputs": [], 249 | "stateMutability": "nonpayable", 250 | "type": "function" 251 | }, 252 | { 253 | "inputs": [ 254 | { 255 | "internalType": "address", 256 | "name": "_from", 257 | "type": "address" 258 | }, 259 | { 260 | "internalType": "uint256", 261 | "name": "_value", 262 | "type": "uint256" 263 | }, 264 | { 265 | "internalType": "bytes", 266 | "name": "_data", 267 | "type": "bytes" 268 | } 269 | ], 270 | "name": "tokenReceived", 271 | "outputs": [ 272 | { 273 | "internalType": "bytes4", 274 | "name": "", 275 | "type": "bytes4" 276 | } 277 | ], 278 | "stateMutability": "nonpayable", 279 | "type": "function" 280 | }, 281 | { 282 | "inputs": [ 283 | { 284 | "internalType": "address", 285 | "name": "_newOwner", 286 | "type": "address" 287 | } 288 | ], 289 | "name": "transferOwnership", 290 | "outputs": [], 291 | "stateMutability": "nonpayable", 292 | "type": "function" 293 | }, 294 | { 295 | "inputs": [ 296 | { 297 | "internalType": "address", 298 | "name": "_ERC20token", 299 | "type": "address" 300 | }, 301 | { 302 | "internalType": "uint256", 303 | "name": "_amount", 304 | "type": "uint256" 305 | } 306 | ], 307 | "name": "unwrapERC20toERC223", 308 | "outputs": [ 309 | { 310 | "internalType": "bool", 311 | "name": "", 312 | "type": "bool" 313 | } 314 | ], 315 | "stateMutability": "nonpayable", 316 | "type": "function" 317 | }, 318 | { 319 | "inputs": [ 320 | { 321 | "internalType": "address", 322 | "name": "_ERC20token", 323 | "type": "address" 324 | }, 325 | { 326 | "internalType": "uint256", 327 | "name": "_amount", 328 | "type": "uint256" 329 | } 330 | ], 331 | "name": "wrapERC20toERC223", 332 | "outputs": [ 333 | { 334 | "internalType": "bool", 335 | "name": "", 336 | "type": "bool" 337 | } 338 | ], 339 | "stateMutability": "nonpayable", 340 | "type": "function" 341 | } 342 | ] 343 | -------------------------------------------------------------------------------- /TokenConverter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | 3 | pragma solidity >=0.8.19; 4 | 5 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/token/ERC223/IERC223Recipient.sol"; 6 | import "https://github.com/Dexaran/ERC223-token-standard/blob/development/utils/Address.sol"; 7 | import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/ERC165.sol"; 8 | 9 | /** 10 | * @dev Interface of the ERC223 standard token as defined in the EIP-223 https://eips.ethereum.org/EIPS/eip-223. 11 | Using a custom IERC223 here as it redefines the "transfer" function as payable. 12 | */ 13 | 14 | abstract contract IERC223 { 15 | 16 | function name() public view virtual returns (string memory); 17 | function symbol() public view virtual returns (string memory); 18 | function decimals() public view virtual returns (uint8); 19 | function totalSupply() public view virtual returns (uint256); 20 | 21 | /** 22 | * @dev Returns the balance of the `who` address. 23 | */ 24 | function balanceOf(address who) public virtual view returns (uint); 25 | 26 | /** 27 | * @dev Transfers `value` tokens from `msg.sender` to `to` address 28 | * and returns `true` on success. 29 | */ 30 | function transfer(address to, uint value) public virtual returns (bool success); 31 | 32 | /** 33 | * @dev Transfers `value` tokens from `msg.sender` to `to` address with `data` parameter 34 | * and returns `true` on success. 35 | */ 36 | function transfer(address to, uint value, bytes calldata data) public payable virtual returns (bool success); 37 | 38 | /** 39 | * @dev Event that is fired on successful transfer. 40 | */ 41 | event Transfer(address indexed from, address indexed to, uint value, bytes data); 42 | } 43 | 44 | /** 45 | * @dev Interface of the ERC20 standard as defined in the EIP. 46 | */ 47 | interface IERC20 { 48 | function name() external view returns (string memory); 49 | function symbol() external view returns (string memory); 50 | function decimals() external view returns (uint8); 51 | function totalSupply() external view returns (uint256); 52 | function balanceOf(address account) external view returns (uint256); 53 | function transfer(address to, uint256 value) external returns (bool); 54 | function allowance(address owner, address spender) external view returns (uint256); 55 | function approve(address spender, uint256 value) external returns (bool); 56 | function transferFrom(address from, address to, uint256 value) external returns (bool); 57 | } 58 | 59 | interface standardERC20 60 | { 61 | event Transfer(address indexed from, address indexed to, uint256 value); 62 | event Approval(address indexed owner, address indexed spender, uint256 value); 63 | function totalSupply() external view returns (uint256); 64 | function balanceOf(address account) external view returns (uint256); 65 | function transfer(address to, uint256 value) external returns (bool); 66 | function allowance(address owner, address spender) external view returns (uint256); 67 | function approve(address spender, uint256 value) external returns (bool); 68 | function transferFrom(address from, address to, uint256 value) external returns (bool); 69 | } 70 | 71 | /** 72 | * @dev Interface of the ERC20 standard as defined in the EIP. 73 | */ 74 | interface IERC223WrapperToken { 75 | function name() external view returns (string memory); 76 | function symbol() external view returns (string memory); 77 | function decimals() external view returns (uint8); 78 | function standard() external view returns (string memory); 79 | function origin() external view returns (address); 80 | 81 | function totalSupply() external view returns (uint256); 82 | function balanceOf(address account) external view returns (uint256); 83 | function transfer(address to, uint256 value) external payable returns (bool); 84 | function transfer(address to, uint256 value, bytes calldata data) external payable returns (bool); 85 | function allowance(address owner, address spender) external view returns (uint256); 86 | function approve(address spender, uint256 value) external returns (bool); 87 | function transferFrom(address from, address to, uint256 value) external returns (bool); 88 | 89 | function mint(address _recipient, uint256 _quantity) external; 90 | function burn(address _recipient, uint256 _quantity) external; 91 | } 92 | 93 | interface IERC20WrapperToken { 94 | function name() external view returns (string memory); 95 | function symbol() external view returns (string memory); 96 | function decimals() external view returns (uint8); 97 | function standard() external view returns (string memory); 98 | function origin() external view returns (address); 99 | 100 | function totalSupply() external view returns (uint256); 101 | function balanceOf(address account) external view returns (uint256); 102 | function transfer(address to, uint256 value) external returns (bool); 103 | function allowance(address owner, address spender) external view returns (uint256); 104 | function approve(address spender, uint256 value) external returns (bool); 105 | function transferFrom(address from, address to, uint256 value) external returns (bool); 106 | 107 | function mint(address _recipient, uint256 _quantity) external; 108 | function burn(address _recipient, uint256 _quantity) external; 109 | } 110 | 111 | 112 | /** 113 | ERC-223 Wrapper is a token that is created by the TokenConverter contract 114 | and can be exchanged 1:1 for it's original ERC-20 version at any time 115 | this version implements `approve` and `transferFrom` features for backwards compatibility reasons 116 | even though we do not recommend using this pattern to transfer ERC-223 tokens. 117 | */ 118 | 119 | contract ERC223WrapperToken is IERC223, ERC165 120 | { 121 | address public creator = msg.sender; 122 | address private wrapper_for; 123 | 124 | mapping(address account => mapping(address spender => uint256)) private allowances; 125 | 126 | event Transfer(address indexed from, address indexed to, uint256 amount); 127 | event TransferData(bytes data); 128 | event Approval(address indexed owner, address indexed spender, uint256 amount); 129 | 130 | /* 131 | constructor(address _wrapper_for) 132 | { 133 | wrapper_for = _wrapper_for; 134 | } 135 | */ 136 | 137 | function set(address _wrapper_for) external 138 | { 139 | require(msg.sender == creator); 140 | wrapper_for = _wrapper_for; 141 | } 142 | 143 | uint256 private _totalSupply; 144 | 145 | mapping(address => uint256) private balances; // List of user balances. 146 | 147 | function totalSupply() public view override returns (uint256) { return _totalSupply; } 148 | function balanceOf(address _owner) public view override returns (uint256) { return balances[_owner]; } 149 | 150 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 151 | return 152 | interfaceId == type(IERC20).interfaceId || 153 | interfaceId == type(standardERC20).interfaceId || 154 | interfaceId == type(IERC223WrapperToken).interfaceId || 155 | interfaceId == type(IERC223).interfaceId || 156 | super.supportsInterface(interfaceId); 157 | } 158 | 159 | function transfer(address _to, uint _value, bytes calldata _data) public payable override returns (bool success) 160 | { 161 | balances[msg.sender] = balances[msg.sender] - _value; 162 | balances[_to] = balances[_to] + _value; 163 | if(Address.isContract(_to)) { 164 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data); 165 | } 166 | if (msg.value > 0) payable(_to).transfer(msg.value); 167 | emit Transfer(msg.sender, _to, _value, _data); 168 | emit Transfer(msg.sender, _to, _value); // Old ERC-20 compatible event. Added for backwards compatibility reasons. 169 | 170 | return true; 171 | } 172 | 173 | function transfer(address _to, uint _value) public override returns (bool success) 174 | { 175 | bytes memory _empty = hex"00000000"; 176 | balances[msg.sender] = balances[msg.sender] - _value; 177 | balances[_to] = balances[_to] + _value; 178 | if(Address.isContract(_to)) { 179 | IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty); 180 | } 181 | emit Transfer(msg.sender, _to, _value, _empty); 182 | emit Transfer(msg.sender, _to, _value); // Old ERC-20 compatible event. Added for backwards compatibility reasons. 183 | 184 | return true; 185 | } 186 | 187 | function name() public view override returns (string memory) { return IERC20(wrapper_for).name(); } 188 | function symbol() public view override returns (string memory) { return string.concat(IERC20(wrapper_for).name(), "223"); } 189 | function decimals() public view override returns (uint8) { return IERC20(wrapper_for).decimals(); } 190 | function standard() public view returns (string memory) { return "223"; } 191 | function origin() public view returns (address) { return wrapper_for; } 192 | 193 | function mint(address _recipient, uint256 _quantity) external 194 | { 195 | require(msg.sender == creator, "Wrapper Token: Only the creator contract can mint wrapper tokens."); 196 | balances[_recipient] += _quantity; 197 | _totalSupply += _quantity; 198 | } 199 | 200 | function burn(uint256 _quantity) external 201 | { 202 | require(msg.sender == creator, "Wrapper Token: Only the creator contract can destroy wrapper tokens."); 203 | balances[msg.sender] -= _quantity; 204 | _totalSupply -= _quantity; 205 | } 206 | 207 | // ERC-20 functions for backwards compatibility. 208 | 209 | function allowance(address owner, address spender) public view virtual returns (uint256) { 210 | return allowances[owner][spender]; 211 | } 212 | 213 | function approve(address _spender, uint _value) public returns (bool) { 214 | 215 | // Safety checks. 216 | require(_spender != address(0), "ERC-223: Spender error."); 217 | 218 | allowances[msg.sender][_spender] = _value; 219 | emit Approval(msg.sender, _spender, _value); 220 | 221 | return true; 222 | } 223 | 224 | function transferFrom(address _from, address _to, uint _value) public returns (bool) { 225 | 226 | require(allowances[_from][msg.sender] >= _value, "ERC-223: Insufficient allowance."); 227 | 228 | balances[_from] -= _value; 229 | allowances[_from][msg.sender] -= _value; 230 | balances[_to] += _value; 231 | 232 | emit Transfer(_from, _to, _value); 233 | 234 | return true; 235 | } 236 | } 237 | 238 | contract ERC20WrapperToken is IERC20, ERC165 239 | { 240 | address public creator = msg.sender; 241 | address public wrapper_for; 242 | 243 | mapping(address account => mapping(address spender => uint256)) private allowances; 244 | 245 | event Transfer(address indexed from, address indexed to, uint256 amount); 246 | event Approval(address indexed owner, address indexed spender, uint256 amount); 247 | 248 | /* 249 | constructor(address _wrapper_for) 250 | { 251 | wrapper_for = _wrapper_for; 252 | } 253 | */ 254 | 255 | function set(address _wrapper_for) external 256 | { 257 | require(msg.sender == creator); 258 | wrapper_for = _wrapper_for; 259 | } 260 | 261 | uint256 private _totalSupply; 262 | mapping(address => uint256) private balances; // List of user balances. 263 | 264 | 265 | function balanceOf(address _owner) public view override returns (uint256) { return balances[_owner]; } 266 | 267 | function name() public view override returns (string memory) { return IERC20(wrapper_for).name(); } 268 | function symbol() public view override returns (string memory) { return string.concat(IERC223(wrapper_for).name(), "20"); } 269 | function decimals() public view override returns (uint8) { return IERC20(wrapper_for).decimals(); } 270 | function totalSupply() public view override returns (uint256) { return _totalSupply; } 271 | function origin() public view returns (address) { return wrapper_for; } 272 | 273 | function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { 274 | return 275 | interfaceId == type(IERC20).interfaceId || 276 | interfaceId == type(IERC20WrapperToken).interfaceId || 277 | super.supportsInterface(interfaceId); 278 | } 279 | 280 | function transfer(address _to, uint _value) public override returns (bool success) 281 | { 282 | balances[msg.sender] = balances[msg.sender] - _value; 283 | balances[_to] = balances[_to] + _value; 284 | emit Transfer(msg.sender, _to, _value); 285 | return true; 286 | } 287 | 288 | function mint(address _recipient, uint256 _quantity) external 289 | { 290 | require(msg.sender == creator, "Wrapper Token: Only the creator contract can mint wrapper tokens."); 291 | balances[_recipient] += _quantity; 292 | _totalSupply += _quantity; 293 | } 294 | 295 | function burn(address _from, uint256 _quantity) external 296 | { 297 | require(msg.sender == creator, "Wrapper Token: Only the creator contract can destroy wrapper tokens."); 298 | balances[_from] -= _quantity; 299 | _totalSupply -= _quantity; 300 | } 301 | 302 | function allowance(address owner, address spender) public view virtual returns (uint256) { 303 | return allowances[owner][spender]; 304 | } 305 | 306 | function approve(address _spender, uint _value) public returns (bool) { 307 | 308 | // Safety checks. 309 | 310 | require(_spender != address(0), "ERC-20: Spender error."); 311 | 312 | allowances[msg.sender][_spender] = _value; 313 | emit Approval(msg.sender, _spender, _value); 314 | 315 | return true; 316 | } 317 | 318 | function transferFrom(address _from, address _to, uint _value) public returns (bool) { 319 | 320 | require(allowances[_from][msg.sender] >= _value, "ERC-20: Insufficient allowance."); 321 | 322 | balances[_from] -= _value; 323 | allowances[_from][msg.sender] -= _value; 324 | balances[_to] += _value; 325 | 326 | emit Transfer(_from, _to, _value); 327 | 328 | return true; 329 | } 330 | } 331 | 332 | contract TokenStandardConverter is IERC223Recipient 333 | { 334 | address public ownerMultisig; 335 | 336 | event ERC223WrapperCreated(address indexed _token, address indexed _ERC223Wrapper); 337 | event ERC20WrapperCreated(address indexed _token, address indexed _ERC20Wrapper); 338 | 339 | mapping (address => ERC223WrapperToken) public erc223Wrappers; // A list of token wrappers. First one is ERC-20 origin, second one is ERC-223 version. 340 | mapping (address => ERC20WrapperToken) public erc20Wrappers; 341 | 342 | mapping (address => address) public erc223Origins; 343 | mapping (address => address) public erc20Origins; 344 | mapping (address => uint256) public erc20Supply; // Token => how much was deposited. 345 | 346 | function getERC20WrapperFor(address _token) public view returns (address, string memory) 347 | { 348 | if ( address(erc20Wrappers[_token]) != address(0) ) 349 | { 350 | return (address(erc20Wrappers[_token]), "ERC-20"); 351 | } 352 | 353 | return (address(0), "Error"); 354 | } 355 | 356 | function getERC223WrapperFor(address _token) public view returns (address, string memory) 357 | { 358 | if ( address(erc223Wrappers[_token]) != address(0) ) 359 | { 360 | return (address(erc223Wrappers[_token]), "ERC-223"); 361 | } 362 | 363 | return (address(0), "Error"); 364 | } 365 | 366 | function getERC20OriginFor(address _token) public view returns (address) 367 | { 368 | return (address(erc20Origins[_token])); 369 | } 370 | 371 | function getERC223OriginFor(address _token) public view returns (address) 372 | { 373 | return (address(erc223Origins[_token])); 374 | } 375 | 376 | function predictWrapperAddress(address _token, bool _isERC20) view external returns (address) 377 | { 378 | bytes memory _bytecode; 379 | if(_isERC20) 380 | { 381 | _bytecode= type(ERC223WrapperToken).creationCode; 382 | } 383 | else 384 | { 385 | _bytecode= type(ERC20WrapperToken).creationCode; 386 | } 387 | 388 | bytes32 hash = keccak256( 389 | abi.encodePacked( 390 | bytes1(0xff), address(this), keccak256(abi.encode(_token)), keccak256(_bytecode) 391 | ) 392 | ); 393 | 394 | return address(uint160(uint(hash))); 395 | } 396 | 397 | function tokenReceived(address _from, uint _value, bytes memory _data) public override returns (bytes4) 398 | { 399 | require(erc223Origins[msg.sender] == address(0), "Error: creating wrapper for a wrapper token."); 400 | // There are two possible cases: 401 | // 1. A user deposited ERC-223 origin token to convert it to ERC-20 wrapper 402 | // 2. A user deposited ERC-223 wrapper token to unwrap it to ERC-20 origin. 403 | 404 | if(erc20Origins[msg.sender] != address(0)) 405 | { 406 | // Origin for deposited token exists. 407 | // Unwrap ERC-223 wrapper. 408 | 409 | safeTransfer(erc20Origins[msg.sender], _from, _value); 410 | 411 | erc20Supply[erc20Origins[msg.sender]] -= _value; 412 | //erc223Wrappers[msg.sender].burn(_value); 413 | ERC223WrapperToken(msg.sender).burn(_value); 414 | 415 | return this.tokenReceived.selector; 416 | } 417 | // Otherwise origin for the sender token doesn't exist 418 | // There are two possible cases: 419 | // 1. ERC-20 wrapper for the deposited token exists 420 | // 2. ERC-20 wrapper for the deposited token doesn't exist and must be created. 421 | else if(address(erc20Wrappers[msg.sender]) == address(0)) 422 | { 423 | // Create ERC-20 wrapper if it doesn't exist. 424 | createERC20Wrapper(msg.sender); 425 | } 426 | 427 | // Mint ERC-20 wrapper tokens for the deposited ERC-223 token 428 | // if the ERC-20 wrapper didn't exist then it was just created in the above statement. 429 | erc20Wrappers[msg.sender].mint(_from, _value); 430 | return this.tokenReceived.selector; 431 | } 432 | 433 | function createERC223Wrapper(address _token) public returns (address) 434 | { 435 | require(address(erc223Wrappers[_token]) == address(0), "ERROR: Wrapper exists"); 436 | require(getERC20OriginFor(_token) == address(0), "ERROR: 20 wrapper creation"); 437 | require(getERC223OriginFor(_token) == address(0), "ERROR: 223 wrapper creation"); 438 | 439 | //ERC223WrapperToken _newERC223Wrapper = new ERC223WrapperToken(_token); 440 | ERC223WrapperToken _newERC223Wrapper = new ERC223WrapperToken{salt: keccak256(abi.encode(_token))}(); 441 | _newERC223Wrapper.set(_token); 442 | erc223Wrappers[_token] = _newERC223Wrapper; 443 | erc20Origins[address(_newERC223Wrapper)] = _token; 444 | 445 | emit ERC223WrapperCreated(_token, address(_newERC223Wrapper)); 446 | return address(_newERC223Wrapper); 447 | } 448 | 449 | function createERC20Wrapper(address _token) public returns (address) 450 | { 451 | require(address(erc20Wrappers[_token]) == address(0), "ERROR: Wrapper already exists."); 452 | require(getERC20OriginFor(_token) == address(0), "ERROR: 20 wrapper creation"); 453 | require(getERC223OriginFor(_token) == address(0), "ERROR: 223 wrapper creation"); 454 | 455 | ERC20WrapperToken _newERC20Wrapper = new ERC20WrapperToken{salt: keccak256(abi.encode(_token))}(); 456 | _newERC20Wrapper.set(_token); 457 | erc20Wrappers[_token] = _newERC20Wrapper; 458 | erc223Origins[address(_newERC20Wrapper)] = _token; 459 | 460 | emit ERC20WrapperCreated(_token, address(_newERC20Wrapper)); 461 | return address(_newERC20Wrapper); 462 | } 463 | 464 | function depositERC20(address _token, uint256 _amount) public returns (bool) 465 | { 466 | if(erc223Origins[_token] != address(0)) 467 | { 468 | return unwrapERC20toERC223(_token, _amount); 469 | } 470 | else return wrapERC20toERC223(_token, _amount); 471 | } 472 | 473 | function wrapERC20toERC223(address _ERC20token, uint256 _amount) public returns (bool) 474 | { 475 | // If there is no active wrapper for a token that user wants to wrap 476 | // then create it. 477 | if(address(erc223Wrappers[_ERC20token]) == address(0)) 478 | { 479 | createERC223Wrapper(_ERC20token); 480 | } 481 | uint256 _converterBalance = IERC20(_ERC20token).balanceOf(address(this)); // Safety variable. 482 | 483 | //IERC20(_ERC20token).transferFrom(msg.sender, address(this), _amount); 484 | safeTransferFrom(_ERC20token, msg.sender, address(this), _amount); 485 | 486 | _amount = IERC20(_ERC20token).balanceOf(address(this)) - _converterBalance; 487 | erc20Supply[_ERC20token] += _amount; 488 | 489 | erc223Wrappers[_ERC20token].mint(msg.sender, _amount); 490 | 491 | return true; 492 | } 493 | 494 | function unwrapERC20toERC223(address _ERC20token, uint256 _amount) public returns (bool) 495 | { 496 | require(IERC20(_ERC20token).balanceOf(msg.sender) >= _amount, "Error: Insufficient balance."); 497 | require(erc223Origins[_ERC20token] != address(0), "Error: provided token is not a ERC-20 wrapper."); 498 | 499 | ERC20WrapperToken(_ERC20token).burn(msg.sender, _amount); 500 | 501 | safeTransfer(erc223Origins[_ERC20token], msg.sender, _amount); 502 | 503 | return true; 504 | } 505 | 506 | function convertERC20(address _token, uint256 _amount) public returns (bool) 507 | { 508 | if(isWrapper(_token)) return unwrapERC20toERC223(_token, _amount); 509 | else return wrapERC20toERC223(_token, _amount); 510 | } 511 | 512 | function isWrapper(address _token) public view returns (bool) 513 | { 514 | return erc20Origins[_token] != address(0) || erc223Origins[_token] != address(0); 515 | } 516 | 517 | /* 518 | function convertERC223toERC20(address _from, uint256 _amount) public returns (bool) 519 | { 520 | // If there is no active wrapper for a token that user wants to wrap 521 | // then create it. 522 | if(address(erc20Wrappers[msg.sender]) == address(0)) 523 | { 524 | createERC223Wrapper(msg.sender); 525 | } 526 | 527 | erc20Wrappers[msg.sender].mint(_from, _amount); 528 | 529 | return true; 530 | } 531 | */ 532 | 533 | function rescueERC20(address _token) external { 534 | require(msg.sender == ownerMultisig, "ERROR: Only owner can do this."); 535 | require(address(erc20Wrappers[_token]) == address(0), "Withdrawing ERC-223 origin is not allowed."); 536 | uint256 _stuckTokens = IERC20(_token).balanceOf(address(this)) - erc20Supply[_token]; 537 | //IERC20(_token).transfer(msg.sender, _stuckTokens); 538 | safeTransfer(_token, msg.sender, _stuckTokens); 539 | } 540 | 541 | function transferOwnership(address _newOwner) public 542 | { 543 | require(msg.sender == ownerMultisig, "ERROR: Only owner can call this function."); 544 | ownerMultisig = _newOwner; 545 | } 546 | 547 | // ************************************************************ 548 | // Functions that address problems with tokens that pretend to be ERC-20 549 | // but in fact are not compatible with the ERC-20 standard transferring methods. 550 | // EIP20 https://eips.ethereum.org/EIPS/eip-20 551 | // ************************************************************ 552 | function safeTransfer(address token, address to, uint value) internal { 553 | // bytes4(keccak256(bytes('transfer(address,uint256)'))); 554 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); 555 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); 556 | } 557 | 558 | function safeTransferFrom(address token, address from, address to, uint value) internal { 559 | // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); 560 | (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); 561 | require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); 562 | } 563 | } 564 | --------------------------------------------------------------------------------