├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── abi ├── token.abi └── token.go ├── contracts ├── BEP20Token.sol ├── Context.sol ├── IBEP20.sol ├── IERC900.sol ├── ITokenHub.sol ├── ITokenManager.sol ├── Migrations.sol ├── MultiSendWallet.sol ├── MultiSendWalletFactory.sol ├── MultiSendableToken.sol ├── Ownable.sol ├── SafeMath.sol ├── Staking.sol ├── Token.sol └── TokenMultiSendWrapper.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_token.js ├── package-lock.json ├── package.json ├── scripts ├── approveTokens.js ├── bindTokenContract.js ├── exportABIs.js ├── transfer.js └── transferOutToBC.js ├── test ├── stakeTest.js ├── tokenTest.js └── walletTest.js └── truffle-config.js /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true, 3 | "solidity.enableLocalNodeCompiler": false, 4 | "solidity.compileUsingRemoteVersion": "v0.5.16+commit.9c3226ce" 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Swingby Labs PTE LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BEP20Token 2 | 3 | ## Requrements 4 | - truffle v5.1.43 (Solidity v0.5.16 (solc-js), Node v14.8.0, Web3.js v1.2.1) 5 | - ganache test rpc. 6 | 7 | ## Getting started 8 | ``` 9 | $ npm install 10 | ``` 11 | 12 | ## Deploy BEP-20 token 13 | ``` 14 | $ export SEED= 15 | $ truffle migrate --network {development/bsc_testnet} 16 | ``` 17 | ## Binding BEP20 token to BEP-2 token (for bsc_testnet) 18 | Please have a look this [instuction](https://github.com/binance-chain/token-bind-tool#bind-bep2-token-with-bep20-token) and make sure all of requrements for binding. 19 | 20 | ### Step 1. Import your key to bnbcli 21 | ``` 22 | $ tbnbcli keys add owner --recover 23 | ``` 24 | ### Step 2. BEP-2 token issue (example 1 billion tokens and symbol TESTONE-A43) 25 | ``` 26 | $ tbnbcli token issue --symbol TESTONE --token-name "TEST one token" --total-supply 100000000000000000 --from owner --chain-id Binance-Chain-Ganges --node http://data-seed-pre-0-s3.binance.org:80 27 | ``` 28 | ### Step 3. BEP-20 token issue 29 | See the above deploy command. 30 | You have to check the following things before deploy token. 31 | - Token symbol should have to same (if the BEP-2 token name is `SWINGBY-888`, symbol should be `SWINGBY`) 32 | - Total supply should be same as BEP-2 token supply 33 | - It may be better to disable the `mintable` on the [Token.sol](contracts/Token.sol). 34 | 35 | ### Step 4. Make a binding tx for BC 36 | In thie case, the total supply is `100000000000000000`and `60000000000000000` 600 million BEP-2 tokens will be locked into the pure-code-controlled address on BC. then, `40000000000000000` 400 million BEP-20 tokens will be locked into the tokenManager contract on BSC. 37 | ``` 38 | $ tbnbcli bridge bind --symbol TESTONE-A43 --amount 60000000000000000 --expire-time --contract-decimals 18 --from owner --chain-id Binance-Chain-Ganges --contract-address --node http://data-seed-pre-0-s3.binance.org:80 39 | ``` 40 | ### Step 5. Allowance tokens to token manager contract 41 | ``` 42 | $ AMOUNT=40000000000000000 truffle exec scripts/approveTokens.js --network bsc_testnet 43 | ``` 44 | ### Step 6. Make a binding tx for BSC 45 | ``` 46 | $ SYMBOL=TESTONE-A43 truffle exec scripts/bindTokenContract.js --network bsc_testnet 47 | ``` 48 | ### Step 7. Confirm bind result on BC 49 | ``` 50 | $ tbnbcli token info --symbol TESTONE-A43 --trust-node --node http://data-seed-pre-0-s3.binance.org:80 51 | ``` 52 | 53 | ### TrasnferOut BSC from BC (100 TESTONE-A43 tokens will be transferred to BSC address) 54 | ``` 55 | $ tbnbcli bridge transfer-out --to --expire-time --chain-id Binance-Chain-Ganges --from owner --amount 10000000000:TESTONE-A43 --node http://data-seed-pre-0-s3.binance.org:80 56 | ``` 57 | 58 | ### TransferOut BC from BSC (100 TESTONE-A43 tokens will be transferred to BC address) 59 | ``` 60 | $ AMOUNT= TO= truffle exec scripts/transferOutToBC.js --network bsc_testnet 61 | ``` 62 | 63 | ## Test 64 | ``` 65 | $ truffle test 66 | ``` 67 | -------------------------------------------------------------------------------- /abi/token.abi: -------------------------------------------------------------------------------- 1 | [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event","signature":"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event","signature":"0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event","signature":"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x8da5cb5b"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x715018a6"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xf2fde38b"},{"constant":false,"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xf8f5faa2"},{"constant":true,"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x893d20e8"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x313ce567"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x95d89b41"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x06fdde03"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x18160ddd"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function","signature":"0x70a08231"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xa9059cbb"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function","signature":"0xdd62ed3e"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x095ea7b3"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x23b872dd"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0x39509351"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xa457c2d7"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function","signature":"0xa0712d68"}] -------------------------------------------------------------------------------- /abi/token.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package token 5 | 6 | import ( 7 | "math/big" 8 | "strings" 9 | 10 | ethereum "github.com/ethereum/go-ethereum" 11 | "github.com/ethereum/go-ethereum/accounts/abi" 12 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 13 | "github.com/ethereum/go-ethereum/common" 14 | "github.com/ethereum/go-ethereum/core/types" 15 | "github.com/ethereum/go-ethereum/event" 16 | ) 17 | 18 | // Reference imports to suppress errors if they are not otherwise used. 19 | var ( 20 | _ = big.NewInt 21 | _ = strings.NewReader 22 | _ = ethereum.NotFound 23 | _ = bind.Bind 24 | _ = common.Big1 25 | _ = types.BloomLookup 26 | _ = event.NewSubscription 27 | ) 28 | 29 | // TokenABI is the input ABI used to generate the binding from. 30 | const TokenABI = "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\",\"signature\":\"0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\",\"signature\":\"0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\",\"signature\":\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x8da5cb5b\"},{\"constant\":false,\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x715018a6\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xf2fde38b\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"totalSupply\",\"type\":\"uint256\"}],\"name\":\"init\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xf8f5faa2\"},{\"constant\":true,\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x893d20e8\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x313ce567\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x95d89b41\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x06fdde03\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x18160ddd\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0x70a08231\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xa9059cbb\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\",\"signature\":\"0xdd62ed3e\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x095ea7b3\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x23b872dd\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0x39509351\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xa457c2d7\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\",\"signature\":\"0xa0712d68\"}]" 31 | 32 | // Token is an auto generated Go binding around an Ethereum contract. 33 | type Token struct { 34 | TokenCaller // Read-only binding to the contract 35 | TokenTransactor // Write-only binding to the contract 36 | TokenFilterer // Log filterer for contract events 37 | } 38 | 39 | // TokenCaller is an auto generated read-only Go binding around an Ethereum contract. 40 | type TokenCaller struct { 41 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 42 | } 43 | 44 | // TokenTransactor is an auto generated write-only Go binding around an Ethereum contract. 45 | type TokenTransactor struct { 46 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 47 | } 48 | 49 | // TokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. 50 | type TokenFilterer struct { 51 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 52 | } 53 | 54 | // TokenSession is an auto generated Go binding around an Ethereum contract, 55 | // with pre-set call and transact options. 56 | type TokenSession struct { 57 | Contract *Token // Generic contract binding to set the session for 58 | CallOpts bind.CallOpts // Call options to use throughout this session 59 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 60 | } 61 | 62 | // TokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, 63 | // with pre-set call options. 64 | type TokenCallerSession struct { 65 | Contract *TokenCaller // Generic contract caller binding to set the session for 66 | CallOpts bind.CallOpts // Call options to use throughout this session 67 | } 68 | 69 | // TokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, 70 | // with pre-set transact options. 71 | type TokenTransactorSession struct { 72 | Contract *TokenTransactor // Generic contract transactor binding to set the session for 73 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 74 | } 75 | 76 | // TokenRaw is an auto generated low-level Go binding around an Ethereum contract. 77 | type TokenRaw struct { 78 | Contract *Token // Generic contract binding to access the raw methods on 79 | } 80 | 81 | // TokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. 82 | type TokenCallerRaw struct { 83 | Contract *TokenCaller // Generic read-only contract binding to access the raw methods on 84 | } 85 | 86 | // TokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. 87 | type TokenTransactorRaw struct { 88 | Contract *TokenTransactor // Generic write-only contract binding to access the raw methods on 89 | } 90 | 91 | // NewToken creates a new instance of Token, bound to a specific deployed contract. 92 | func NewToken(address common.Address, backend bind.ContractBackend) (*Token, error) { 93 | contract, err := bindToken(address, backend, backend, backend) 94 | if err != nil { 95 | return nil, err 96 | } 97 | return &Token{TokenCaller: TokenCaller{contract: contract}, TokenTransactor: TokenTransactor{contract: contract}, TokenFilterer: TokenFilterer{contract: contract}}, nil 98 | } 99 | 100 | // NewTokenCaller creates a new read-only instance of Token, bound to a specific deployed contract. 101 | func NewTokenCaller(address common.Address, caller bind.ContractCaller) (*TokenCaller, error) { 102 | contract, err := bindToken(address, caller, nil, nil) 103 | if err != nil { 104 | return nil, err 105 | } 106 | return &TokenCaller{contract: contract}, nil 107 | } 108 | 109 | // NewTokenTransactor creates a new write-only instance of Token, bound to a specific deployed contract. 110 | func NewTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*TokenTransactor, error) { 111 | contract, err := bindToken(address, nil, transactor, nil) 112 | if err != nil { 113 | return nil, err 114 | } 115 | return &TokenTransactor{contract: contract}, nil 116 | } 117 | 118 | // NewTokenFilterer creates a new log filterer instance of Token, bound to a specific deployed contract. 119 | func NewTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*TokenFilterer, error) { 120 | contract, err := bindToken(address, nil, nil, filterer) 121 | if err != nil { 122 | return nil, err 123 | } 124 | return &TokenFilterer{contract: contract}, nil 125 | } 126 | 127 | // bindToken binds a generic wrapper to an already deployed contract. 128 | func bindToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 129 | parsed, err := abi.JSON(strings.NewReader(TokenABI)) 130 | if err != nil { 131 | return nil, err 132 | } 133 | return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil 134 | } 135 | 136 | // Call invokes the (constant) contract method with params as input values and 137 | // sets the output to result. The result type might be a single field for simple 138 | // returns, a slice of interfaces for anonymous returns and a struct for named 139 | // returns. 140 | func (_Token *TokenRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 141 | return _Token.Contract.TokenCaller.contract.Call(opts, result, method, params...) 142 | } 143 | 144 | // Transfer initiates a plain transaction to move funds to the contract, calling 145 | // its default method if one is available. 146 | func (_Token *TokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 147 | return _Token.Contract.TokenTransactor.contract.Transfer(opts) 148 | } 149 | 150 | // Transact invokes the (paid) contract method with params as input values. 151 | func (_Token *TokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 152 | return _Token.Contract.TokenTransactor.contract.Transact(opts, method, params...) 153 | } 154 | 155 | // Call invokes the (constant) contract method with params as input values and 156 | // sets the output to result. The result type might be a single field for simple 157 | // returns, a slice of interfaces for anonymous returns and a struct for named 158 | // returns. 159 | func (_Token *TokenCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 160 | return _Token.Contract.contract.Call(opts, result, method, params...) 161 | } 162 | 163 | // Transfer initiates a plain transaction to move funds to the contract, calling 164 | // its default method if one is available. 165 | func (_Token *TokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 166 | return _Token.Contract.contract.Transfer(opts) 167 | } 168 | 169 | // Transact invokes the (paid) contract method with params as input values. 170 | func (_Token *TokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 171 | return _Token.Contract.contract.Transact(opts, method, params...) 172 | } 173 | 174 | // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. 175 | // 176 | // Solidity: function allowance(address owner, address spender) view returns(uint256) 177 | func (_Token *TokenCaller) Allowance(opts *bind.CallOpts, owner common.Address, spender common.Address) (*big.Int, error) { 178 | var ( 179 | ret0 = new(*big.Int) 180 | ) 181 | out := ret0 182 | err := _Token.contract.Call(opts, out, "allowance", owner, spender) 183 | return *ret0, err 184 | } 185 | 186 | // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. 187 | // 188 | // Solidity: function allowance(address owner, address spender) view returns(uint256) 189 | func (_Token *TokenSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { 190 | return _Token.Contract.Allowance(&_Token.CallOpts, owner, spender) 191 | } 192 | 193 | // Allowance is a free data retrieval call binding the contract method 0xdd62ed3e. 194 | // 195 | // Solidity: function allowance(address owner, address spender) view returns(uint256) 196 | func (_Token *TokenCallerSession) Allowance(owner common.Address, spender common.Address) (*big.Int, error) { 197 | return _Token.Contract.Allowance(&_Token.CallOpts, owner, spender) 198 | } 199 | 200 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. 201 | // 202 | // Solidity: function balanceOf(address account) view returns(uint256) 203 | func (_Token *TokenCaller) BalanceOf(opts *bind.CallOpts, account common.Address) (*big.Int, error) { 204 | var ( 205 | ret0 = new(*big.Int) 206 | ) 207 | out := ret0 208 | err := _Token.contract.Call(opts, out, "balanceOf", account) 209 | return *ret0, err 210 | } 211 | 212 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. 213 | // 214 | // Solidity: function balanceOf(address account) view returns(uint256) 215 | func (_Token *TokenSession) BalanceOf(account common.Address) (*big.Int, error) { 216 | return _Token.Contract.BalanceOf(&_Token.CallOpts, account) 217 | } 218 | 219 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. 220 | // 221 | // Solidity: function balanceOf(address account) view returns(uint256) 222 | func (_Token *TokenCallerSession) BalanceOf(account common.Address) (*big.Int, error) { 223 | return _Token.Contract.BalanceOf(&_Token.CallOpts, account) 224 | } 225 | 226 | // Decimals is a free data retrieval call binding the contract method 0x313ce567. 227 | // 228 | // Solidity: function decimals() view returns(uint8) 229 | func (_Token *TokenCaller) Decimals(opts *bind.CallOpts) (uint8, error) { 230 | var ( 231 | ret0 = new(uint8) 232 | ) 233 | out := ret0 234 | err := _Token.contract.Call(opts, out, "decimals") 235 | return *ret0, err 236 | } 237 | 238 | // Decimals is a free data retrieval call binding the contract method 0x313ce567. 239 | // 240 | // Solidity: function decimals() view returns(uint8) 241 | func (_Token *TokenSession) Decimals() (uint8, error) { 242 | return _Token.Contract.Decimals(&_Token.CallOpts) 243 | } 244 | 245 | // Decimals is a free data retrieval call binding the contract method 0x313ce567. 246 | // 247 | // Solidity: function decimals() view returns(uint8) 248 | func (_Token *TokenCallerSession) Decimals() (uint8, error) { 249 | return _Token.Contract.Decimals(&_Token.CallOpts) 250 | } 251 | 252 | // GetOwner is a free data retrieval call binding the contract method 0x893d20e8. 253 | // 254 | // Solidity: function getOwner() view returns(address) 255 | func (_Token *TokenCaller) GetOwner(opts *bind.CallOpts) (common.Address, error) { 256 | var ( 257 | ret0 = new(common.Address) 258 | ) 259 | out := ret0 260 | err := _Token.contract.Call(opts, out, "getOwner") 261 | return *ret0, err 262 | } 263 | 264 | // GetOwner is a free data retrieval call binding the contract method 0x893d20e8. 265 | // 266 | // Solidity: function getOwner() view returns(address) 267 | func (_Token *TokenSession) GetOwner() (common.Address, error) { 268 | return _Token.Contract.GetOwner(&_Token.CallOpts) 269 | } 270 | 271 | // GetOwner is a free data retrieval call binding the contract method 0x893d20e8. 272 | // 273 | // Solidity: function getOwner() view returns(address) 274 | func (_Token *TokenCallerSession) GetOwner() (common.Address, error) { 275 | return _Token.Contract.GetOwner(&_Token.CallOpts) 276 | } 277 | 278 | // Name is a free data retrieval call binding the contract method 0x06fdde03. 279 | // 280 | // Solidity: function name() view returns(string) 281 | func (_Token *TokenCaller) Name(opts *bind.CallOpts) (string, error) { 282 | var ( 283 | ret0 = new(string) 284 | ) 285 | out := ret0 286 | err := _Token.contract.Call(opts, out, "name") 287 | return *ret0, err 288 | } 289 | 290 | // Name is a free data retrieval call binding the contract method 0x06fdde03. 291 | // 292 | // Solidity: function name() view returns(string) 293 | func (_Token *TokenSession) Name() (string, error) { 294 | return _Token.Contract.Name(&_Token.CallOpts) 295 | } 296 | 297 | // Name is a free data retrieval call binding the contract method 0x06fdde03. 298 | // 299 | // Solidity: function name() view returns(string) 300 | func (_Token *TokenCallerSession) Name() (string, error) { 301 | return _Token.Contract.Name(&_Token.CallOpts) 302 | } 303 | 304 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 305 | // 306 | // Solidity: function owner() view returns(address) 307 | func (_Token *TokenCaller) Owner(opts *bind.CallOpts) (common.Address, error) { 308 | var ( 309 | ret0 = new(common.Address) 310 | ) 311 | out := ret0 312 | err := _Token.contract.Call(opts, out, "owner") 313 | return *ret0, err 314 | } 315 | 316 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 317 | // 318 | // Solidity: function owner() view returns(address) 319 | func (_Token *TokenSession) Owner() (common.Address, error) { 320 | return _Token.Contract.Owner(&_Token.CallOpts) 321 | } 322 | 323 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 324 | // 325 | // Solidity: function owner() view returns(address) 326 | func (_Token *TokenCallerSession) Owner() (common.Address, error) { 327 | return _Token.Contract.Owner(&_Token.CallOpts) 328 | } 329 | 330 | // Symbol is a free data retrieval call binding the contract method 0x95d89b41. 331 | // 332 | // Solidity: function symbol() view returns(string) 333 | func (_Token *TokenCaller) Symbol(opts *bind.CallOpts) (string, error) { 334 | var ( 335 | ret0 = new(string) 336 | ) 337 | out := ret0 338 | err := _Token.contract.Call(opts, out, "symbol") 339 | return *ret0, err 340 | } 341 | 342 | // Symbol is a free data retrieval call binding the contract method 0x95d89b41. 343 | // 344 | // Solidity: function symbol() view returns(string) 345 | func (_Token *TokenSession) Symbol() (string, error) { 346 | return _Token.Contract.Symbol(&_Token.CallOpts) 347 | } 348 | 349 | // Symbol is a free data retrieval call binding the contract method 0x95d89b41. 350 | // 351 | // Solidity: function symbol() view returns(string) 352 | func (_Token *TokenCallerSession) Symbol() (string, error) { 353 | return _Token.Contract.Symbol(&_Token.CallOpts) 354 | } 355 | 356 | // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. 357 | // 358 | // Solidity: function totalSupply() view returns(uint256) 359 | func (_Token *TokenCaller) TotalSupply(opts *bind.CallOpts) (*big.Int, error) { 360 | var ( 361 | ret0 = new(*big.Int) 362 | ) 363 | out := ret0 364 | err := _Token.contract.Call(opts, out, "totalSupply") 365 | return *ret0, err 366 | } 367 | 368 | // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. 369 | // 370 | // Solidity: function totalSupply() view returns(uint256) 371 | func (_Token *TokenSession) TotalSupply() (*big.Int, error) { 372 | return _Token.Contract.TotalSupply(&_Token.CallOpts) 373 | } 374 | 375 | // TotalSupply is a free data retrieval call binding the contract method 0x18160ddd. 376 | // 377 | // Solidity: function totalSupply() view returns(uint256) 378 | func (_Token *TokenCallerSession) TotalSupply() (*big.Int, error) { 379 | return _Token.Contract.TotalSupply(&_Token.CallOpts) 380 | } 381 | 382 | // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. 383 | // 384 | // Solidity: function approve(address spender, uint256 amount) returns(bool) 385 | func (_Token *TokenTransactor) Approve(opts *bind.TransactOpts, spender common.Address, amount *big.Int) (*types.Transaction, error) { 386 | return _Token.contract.Transact(opts, "approve", spender, amount) 387 | } 388 | 389 | // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. 390 | // 391 | // Solidity: function approve(address spender, uint256 amount) returns(bool) 392 | func (_Token *TokenSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { 393 | return _Token.Contract.Approve(&_Token.TransactOpts, spender, amount) 394 | } 395 | 396 | // Approve is a paid mutator transaction binding the contract method 0x095ea7b3. 397 | // 398 | // Solidity: function approve(address spender, uint256 amount) returns(bool) 399 | func (_Token *TokenTransactorSession) Approve(spender common.Address, amount *big.Int) (*types.Transaction, error) { 400 | return _Token.Contract.Approve(&_Token.TransactOpts, spender, amount) 401 | } 402 | 403 | // DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. 404 | // 405 | // Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) 406 | func (_Token *TokenTransactor) DecreaseAllowance(opts *bind.TransactOpts, spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { 407 | return _Token.contract.Transact(opts, "decreaseAllowance", spender, subtractedValue) 408 | } 409 | 410 | // DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. 411 | // 412 | // Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) 413 | func (_Token *TokenSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { 414 | return _Token.Contract.DecreaseAllowance(&_Token.TransactOpts, spender, subtractedValue) 415 | } 416 | 417 | // DecreaseAllowance is a paid mutator transaction binding the contract method 0xa457c2d7. 418 | // 419 | // Solidity: function decreaseAllowance(address spender, uint256 subtractedValue) returns(bool) 420 | func (_Token *TokenTransactorSession) DecreaseAllowance(spender common.Address, subtractedValue *big.Int) (*types.Transaction, error) { 421 | return _Token.Contract.DecreaseAllowance(&_Token.TransactOpts, spender, subtractedValue) 422 | } 423 | 424 | // IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. 425 | // 426 | // Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) 427 | func (_Token *TokenTransactor) IncreaseAllowance(opts *bind.TransactOpts, spender common.Address, addedValue *big.Int) (*types.Transaction, error) { 428 | return _Token.contract.Transact(opts, "increaseAllowance", spender, addedValue) 429 | } 430 | 431 | // IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. 432 | // 433 | // Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) 434 | func (_Token *TokenSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { 435 | return _Token.Contract.IncreaseAllowance(&_Token.TransactOpts, spender, addedValue) 436 | } 437 | 438 | // IncreaseAllowance is a paid mutator transaction binding the contract method 0x39509351. 439 | // 440 | // Solidity: function increaseAllowance(address spender, uint256 addedValue) returns(bool) 441 | func (_Token *TokenTransactorSession) IncreaseAllowance(spender common.Address, addedValue *big.Int) (*types.Transaction, error) { 442 | return _Token.Contract.IncreaseAllowance(&_Token.TransactOpts, spender, addedValue) 443 | } 444 | 445 | // Init is a paid mutator transaction binding the contract method 0xf8f5faa2. 446 | // 447 | // Solidity: function init(string name, string symbol, uint8 decimals, uint256 totalSupply) returns() 448 | func (_Token *TokenTransactor) Init(opts *bind.TransactOpts, name string, symbol string, decimals uint8, totalSupply *big.Int) (*types.Transaction, error) { 449 | return _Token.contract.Transact(opts, "init", name, symbol, decimals, totalSupply) 450 | } 451 | 452 | // Init is a paid mutator transaction binding the contract method 0xf8f5faa2. 453 | // 454 | // Solidity: function init(string name, string symbol, uint8 decimals, uint256 totalSupply) returns() 455 | func (_Token *TokenSession) Init(name string, symbol string, decimals uint8, totalSupply *big.Int) (*types.Transaction, error) { 456 | return _Token.Contract.Init(&_Token.TransactOpts, name, symbol, decimals, totalSupply) 457 | } 458 | 459 | // Init is a paid mutator transaction binding the contract method 0xf8f5faa2. 460 | // 461 | // Solidity: function init(string name, string symbol, uint8 decimals, uint256 totalSupply) returns() 462 | func (_Token *TokenTransactorSession) Init(name string, symbol string, decimals uint8, totalSupply *big.Int) (*types.Transaction, error) { 463 | return _Token.Contract.Init(&_Token.TransactOpts, name, symbol, decimals, totalSupply) 464 | } 465 | 466 | // Mint is a paid mutator transaction binding the contract method 0xa0712d68. 467 | // 468 | // Solidity: function mint(uint256 amount) returns(bool) 469 | func (_Token *TokenTransactor) Mint(opts *bind.TransactOpts, amount *big.Int) (*types.Transaction, error) { 470 | return _Token.contract.Transact(opts, "mint", amount) 471 | } 472 | 473 | // Mint is a paid mutator transaction binding the contract method 0xa0712d68. 474 | // 475 | // Solidity: function mint(uint256 amount) returns(bool) 476 | func (_Token *TokenSession) Mint(amount *big.Int) (*types.Transaction, error) { 477 | return _Token.Contract.Mint(&_Token.TransactOpts, amount) 478 | } 479 | 480 | // Mint is a paid mutator transaction binding the contract method 0xa0712d68. 481 | // 482 | // Solidity: function mint(uint256 amount) returns(bool) 483 | func (_Token *TokenTransactorSession) Mint(amount *big.Int) (*types.Transaction, error) { 484 | return _Token.Contract.Mint(&_Token.TransactOpts, amount) 485 | } 486 | 487 | // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. 488 | // 489 | // Solidity: function renounceOwnership() returns() 490 | func (_Token *TokenTransactor) RenounceOwnership(opts *bind.TransactOpts) (*types.Transaction, error) { 491 | return _Token.contract.Transact(opts, "renounceOwnership") 492 | } 493 | 494 | // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. 495 | // 496 | // Solidity: function renounceOwnership() returns() 497 | func (_Token *TokenSession) RenounceOwnership() (*types.Transaction, error) { 498 | return _Token.Contract.RenounceOwnership(&_Token.TransactOpts) 499 | } 500 | 501 | // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. 502 | // 503 | // Solidity: function renounceOwnership() returns() 504 | func (_Token *TokenTransactorSession) RenounceOwnership() (*types.Transaction, error) { 505 | return _Token.Contract.RenounceOwnership(&_Token.TransactOpts) 506 | } 507 | 508 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. 509 | // 510 | // Solidity: function transfer(address recipient, uint256 amount) returns(bool) 511 | func (_Token *TokenTransactor) Transfer(opts *bind.TransactOpts, recipient common.Address, amount *big.Int) (*types.Transaction, error) { 512 | return _Token.contract.Transact(opts, "transfer", recipient, amount) 513 | } 514 | 515 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. 516 | // 517 | // Solidity: function transfer(address recipient, uint256 amount) returns(bool) 518 | func (_Token *TokenSession) Transfer(recipient common.Address, amount *big.Int) (*types.Transaction, error) { 519 | return _Token.Contract.Transfer(&_Token.TransactOpts, recipient, amount) 520 | } 521 | 522 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. 523 | // 524 | // Solidity: function transfer(address recipient, uint256 amount) returns(bool) 525 | func (_Token *TokenTransactorSession) Transfer(recipient common.Address, amount *big.Int) (*types.Transaction, error) { 526 | return _Token.Contract.Transfer(&_Token.TransactOpts, recipient, amount) 527 | } 528 | 529 | // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. 530 | // 531 | // Solidity: function transferFrom(address sender, address recipient, uint256 amount) returns(bool) 532 | func (_Token *TokenTransactor) TransferFrom(opts *bind.TransactOpts, sender common.Address, recipient common.Address, amount *big.Int) (*types.Transaction, error) { 533 | return _Token.contract.Transact(opts, "transferFrom", sender, recipient, amount) 534 | } 535 | 536 | // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. 537 | // 538 | // Solidity: function transferFrom(address sender, address recipient, uint256 amount) returns(bool) 539 | func (_Token *TokenSession) TransferFrom(sender common.Address, recipient common.Address, amount *big.Int) (*types.Transaction, error) { 540 | return _Token.Contract.TransferFrom(&_Token.TransactOpts, sender, recipient, amount) 541 | } 542 | 543 | // TransferFrom is a paid mutator transaction binding the contract method 0x23b872dd. 544 | // 545 | // Solidity: function transferFrom(address sender, address recipient, uint256 amount) returns(bool) 546 | func (_Token *TokenTransactorSession) TransferFrom(sender common.Address, recipient common.Address, amount *big.Int) (*types.Transaction, error) { 547 | return _Token.Contract.TransferFrom(&_Token.TransactOpts, sender, recipient, amount) 548 | } 549 | 550 | // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. 551 | // 552 | // Solidity: function transferOwnership(address newOwner) returns() 553 | func (_Token *TokenTransactor) TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*types.Transaction, error) { 554 | return _Token.contract.Transact(opts, "transferOwnership", newOwner) 555 | } 556 | 557 | // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. 558 | // 559 | // Solidity: function transferOwnership(address newOwner) returns() 560 | func (_Token *TokenSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { 561 | return _Token.Contract.TransferOwnership(&_Token.TransactOpts, newOwner) 562 | } 563 | 564 | // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. 565 | // 566 | // Solidity: function transferOwnership(address newOwner) returns() 567 | func (_Token *TokenTransactorSession) TransferOwnership(newOwner common.Address) (*types.Transaction, error) { 568 | return _Token.Contract.TransferOwnership(&_Token.TransactOpts, newOwner) 569 | } 570 | 571 | // TokenApprovalIterator is returned from FilterApproval and is used to iterate over the raw logs and unpacked data for Approval events raised by the Token contract. 572 | type TokenApprovalIterator struct { 573 | Event *TokenApproval // Event containing the contract specifics and raw log 574 | 575 | contract *bind.BoundContract // Generic contract to use for unpacking event data 576 | event string // Event name to use for unpacking event data 577 | 578 | logs chan types.Log // Log channel receiving the found contract events 579 | sub ethereum.Subscription // Subscription for errors, completion and termination 580 | done bool // Whether the subscription completed delivering logs 581 | fail error // Occurred error to stop iteration 582 | } 583 | 584 | // Next advances the iterator to the subsequent event, returning whether there 585 | // are any more events found. In case of a retrieval or parsing error, false is 586 | // returned and Error() can be queried for the exact failure. 587 | func (it *TokenApprovalIterator) Next() bool { 588 | // If the iterator failed, stop iterating 589 | if it.fail != nil { 590 | return false 591 | } 592 | // If the iterator completed, deliver directly whatever's available 593 | if it.done { 594 | select { 595 | case log := <-it.logs: 596 | it.Event = new(TokenApproval) 597 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 598 | it.fail = err 599 | return false 600 | } 601 | it.Event.Raw = log 602 | return true 603 | 604 | default: 605 | return false 606 | } 607 | } 608 | // Iterator still in progress, wait for either a data or an error event 609 | select { 610 | case log := <-it.logs: 611 | it.Event = new(TokenApproval) 612 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 613 | it.fail = err 614 | return false 615 | } 616 | it.Event.Raw = log 617 | return true 618 | 619 | case err := <-it.sub.Err(): 620 | it.done = true 621 | it.fail = err 622 | return it.Next() 623 | } 624 | } 625 | 626 | // Error returns any retrieval or parsing error occurred during filtering. 627 | func (it *TokenApprovalIterator) Error() error { 628 | return it.fail 629 | } 630 | 631 | // Close terminates the iteration process, releasing any pending underlying 632 | // resources. 633 | func (it *TokenApprovalIterator) Close() error { 634 | it.sub.Unsubscribe() 635 | return nil 636 | } 637 | 638 | // TokenApproval represents a Approval event raised by the Token contract. 639 | type TokenApproval struct { 640 | Owner common.Address 641 | Spender common.Address 642 | Value *big.Int 643 | Raw types.Log // Blockchain specific contextual infos 644 | } 645 | 646 | // FilterApproval is a free log retrieval operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. 647 | // 648 | // Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) 649 | func (_Token *TokenFilterer) FilterApproval(opts *bind.FilterOpts, owner []common.Address, spender []common.Address) (*TokenApprovalIterator, error) { 650 | 651 | var ownerRule []interface{} 652 | for _, ownerItem := range owner { 653 | ownerRule = append(ownerRule, ownerItem) 654 | } 655 | var spenderRule []interface{} 656 | for _, spenderItem := range spender { 657 | spenderRule = append(spenderRule, spenderItem) 658 | } 659 | 660 | logs, sub, err := _Token.contract.FilterLogs(opts, "Approval", ownerRule, spenderRule) 661 | if err != nil { 662 | return nil, err 663 | } 664 | return &TokenApprovalIterator{contract: _Token.contract, event: "Approval", logs: logs, sub: sub}, nil 665 | } 666 | 667 | // WatchApproval is a free log subscription operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. 668 | // 669 | // Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) 670 | func (_Token *TokenFilterer) WatchApproval(opts *bind.WatchOpts, sink chan<- *TokenApproval, owner []common.Address, spender []common.Address) (event.Subscription, error) { 671 | 672 | var ownerRule []interface{} 673 | for _, ownerItem := range owner { 674 | ownerRule = append(ownerRule, ownerItem) 675 | } 676 | var spenderRule []interface{} 677 | for _, spenderItem := range spender { 678 | spenderRule = append(spenderRule, spenderItem) 679 | } 680 | 681 | logs, sub, err := _Token.contract.WatchLogs(opts, "Approval", ownerRule, spenderRule) 682 | if err != nil { 683 | return nil, err 684 | } 685 | return event.NewSubscription(func(quit <-chan struct{}) error { 686 | defer sub.Unsubscribe() 687 | for { 688 | select { 689 | case log := <-logs: 690 | // New log arrived, parse the event and forward to the user 691 | event := new(TokenApproval) 692 | if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { 693 | return err 694 | } 695 | event.Raw = log 696 | 697 | select { 698 | case sink <- event: 699 | case err := <-sub.Err(): 700 | return err 701 | case <-quit: 702 | return nil 703 | } 704 | case err := <-sub.Err(): 705 | return err 706 | case <-quit: 707 | return nil 708 | } 709 | } 710 | }), nil 711 | } 712 | 713 | // ParseApproval is a log parse operation binding the contract event 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925. 714 | // 715 | // Solidity: event Approval(address indexed owner, address indexed spender, uint256 value) 716 | func (_Token *TokenFilterer) ParseApproval(log types.Log) (*TokenApproval, error) { 717 | event := new(TokenApproval) 718 | if err := _Token.contract.UnpackLog(event, "Approval", log); err != nil { 719 | return nil, err 720 | } 721 | return event, nil 722 | } 723 | 724 | // TokenOwnershipTransferredIterator is returned from FilterOwnershipTransferred and is used to iterate over the raw logs and unpacked data for OwnershipTransferred events raised by the Token contract. 725 | type TokenOwnershipTransferredIterator struct { 726 | Event *TokenOwnershipTransferred // Event containing the contract specifics and raw log 727 | 728 | contract *bind.BoundContract // Generic contract to use for unpacking event data 729 | event string // Event name to use for unpacking event data 730 | 731 | logs chan types.Log // Log channel receiving the found contract events 732 | sub ethereum.Subscription // Subscription for errors, completion and termination 733 | done bool // Whether the subscription completed delivering logs 734 | fail error // Occurred error to stop iteration 735 | } 736 | 737 | // Next advances the iterator to the subsequent event, returning whether there 738 | // are any more events found. In case of a retrieval or parsing error, false is 739 | // returned and Error() can be queried for the exact failure. 740 | func (it *TokenOwnershipTransferredIterator) Next() bool { 741 | // If the iterator failed, stop iterating 742 | if it.fail != nil { 743 | return false 744 | } 745 | // If the iterator completed, deliver directly whatever's available 746 | if it.done { 747 | select { 748 | case log := <-it.logs: 749 | it.Event = new(TokenOwnershipTransferred) 750 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 751 | it.fail = err 752 | return false 753 | } 754 | it.Event.Raw = log 755 | return true 756 | 757 | default: 758 | return false 759 | } 760 | } 761 | // Iterator still in progress, wait for either a data or an error event 762 | select { 763 | case log := <-it.logs: 764 | it.Event = new(TokenOwnershipTransferred) 765 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 766 | it.fail = err 767 | return false 768 | } 769 | it.Event.Raw = log 770 | return true 771 | 772 | case err := <-it.sub.Err(): 773 | it.done = true 774 | it.fail = err 775 | return it.Next() 776 | } 777 | } 778 | 779 | // Error returns any retrieval or parsing error occurred during filtering. 780 | func (it *TokenOwnershipTransferredIterator) Error() error { 781 | return it.fail 782 | } 783 | 784 | // Close terminates the iteration process, releasing any pending underlying 785 | // resources. 786 | func (it *TokenOwnershipTransferredIterator) Close() error { 787 | it.sub.Unsubscribe() 788 | return nil 789 | } 790 | 791 | // TokenOwnershipTransferred represents a OwnershipTransferred event raised by the Token contract. 792 | type TokenOwnershipTransferred struct { 793 | PreviousOwner common.Address 794 | NewOwner common.Address 795 | Raw types.Log // Blockchain specific contextual infos 796 | } 797 | 798 | // FilterOwnershipTransferred is a free log retrieval operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. 799 | // 800 | // Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) 801 | func (_Token *TokenFilterer) FilterOwnershipTransferred(opts *bind.FilterOpts, previousOwner []common.Address, newOwner []common.Address) (*TokenOwnershipTransferredIterator, error) { 802 | 803 | var previousOwnerRule []interface{} 804 | for _, previousOwnerItem := range previousOwner { 805 | previousOwnerRule = append(previousOwnerRule, previousOwnerItem) 806 | } 807 | var newOwnerRule []interface{} 808 | for _, newOwnerItem := range newOwner { 809 | newOwnerRule = append(newOwnerRule, newOwnerItem) 810 | } 811 | 812 | logs, sub, err := _Token.contract.FilterLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) 813 | if err != nil { 814 | return nil, err 815 | } 816 | return &TokenOwnershipTransferredIterator{contract: _Token.contract, event: "OwnershipTransferred", logs: logs, sub: sub}, nil 817 | } 818 | 819 | // WatchOwnershipTransferred is a free log subscription operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. 820 | // 821 | // Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) 822 | func (_Token *TokenFilterer) WatchOwnershipTransferred(opts *bind.WatchOpts, sink chan<- *TokenOwnershipTransferred, previousOwner []common.Address, newOwner []common.Address) (event.Subscription, error) { 823 | 824 | var previousOwnerRule []interface{} 825 | for _, previousOwnerItem := range previousOwner { 826 | previousOwnerRule = append(previousOwnerRule, previousOwnerItem) 827 | } 828 | var newOwnerRule []interface{} 829 | for _, newOwnerItem := range newOwner { 830 | newOwnerRule = append(newOwnerRule, newOwnerItem) 831 | } 832 | 833 | logs, sub, err := _Token.contract.WatchLogs(opts, "OwnershipTransferred", previousOwnerRule, newOwnerRule) 834 | if err != nil { 835 | return nil, err 836 | } 837 | return event.NewSubscription(func(quit <-chan struct{}) error { 838 | defer sub.Unsubscribe() 839 | for { 840 | select { 841 | case log := <-logs: 842 | // New log arrived, parse the event and forward to the user 843 | event := new(TokenOwnershipTransferred) 844 | if err := _Token.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { 845 | return err 846 | } 847 | event.Raw = log 848 | 849 | select { 850 | case sink <- event: 851 | case err := <-sub.Err(): 852 | return err 853 | case <-quit: 854 | return nil 855 | } 856 | case err := <-sub.Err(): 857 | return err 858 | case <-quit: 859 | return nil 860 | } 861 | } 862 | }), nil 863 | } 864 | 865 | // ParseOwnershipTransferred is a log parse operation binding the contract event 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0. 866 | // 867 | // Solidity: event OwnershipTransferred(address indexed previousOwner, address indexed newOwner) 868 | func (_Token *TokenFilterer) ParseOwnershipTransferred(log types.Log) (*TokenOwnershipTransferred, error) { 869 | event := new(TokenOwnershipTransferred) 870 | if err := _Token.contract.UnpackLog(event, "OwnershipTransferred", log); err != nil { 871 | return nil, err 872 | } 873 | return event, nil 874 | } 875 | 876 | // TokenTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the Token contract. 877 | type TokenTransferIterator struct { 878 | Event *TokenTransfer // Event containing the contract specifics and raw log 879 | 880 | contract *bind.BoundContract // Generic contract to use for unpacking event data 881 | event string // Event name to use for unpacking event data 882 | 883 | logs chan types.Log // Log channel receiving the found contract events 884 | sub ethereum.Subscription // Subscription for errors, completion and termination 885 | done bool // Whether the subscription completed delivering logs 886 | fail error // Occurred error to stop iteration 887 | } 888 | 889 | // Next advances the iterator to the subsequent event, returning whether there 890 | // are any more events found. In case of a retrieval or parsing error, false is 891 | // returned and Error() can be queried for the exact failure. 892 | func (it *TokenTransferIterator) Next() bool { 893 | // If the iterator failed, stop iterating 894 | if it.fail != nil { 895 | return false 896 | } 897 | // If the iterator completed, deliver directly whatever's available 898 | if it.done { 899 | select { 900 | case log := <-it.logs: 901 | it.Event = new(TokenTransfer) 902 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 903 | it.fail = err 904 | return false 905 | } 906 | it.Event.Raw = log 907 | return true 908 | 909 | default: 910 | return false 911 | } 912 | } 913 | // Iterator still in progress, wait for either a data or an error event 914 | select { 915 | case log := <-it.logs: 916 | it.Event = new(TokenTransfer) 917 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 918 | it.fail = err 919 | return false 920 | } 921 | it.Event.Raw = log 922 | return true 923 | 924 | case err := <-it.sub.Err(): 925 | it.done = true 926 | it.fail = err 927 | return it.Next() 928 | } 929 | } 930 | 931 | // Error returns any retrieval or parsing error occurred during filtering. 932 | func (it *TokenTransferIterator) Error() error { 933 | return it.fail 934 | } 935 | 936 | // Close terminates the iteration process, releasing any pending underlying 937 | // resources. 938 | func (it *TokenTransferIterator) Close() error { 939 | it.sub.Unsubscribe() 940 | return nil 941 | } 942 | 943 | // TokenTransfer represents a Transfer event raised by the Token contract. 944 | type TokenTransfer struct { 945 | From common.Address 946 | To common.Address 947 | Value *big.Int 948 | Raw types.Log // Blockchain specific contextual infos 949 | } 950 | 951 | // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. 952 | // 953 | // Solidity: event Transfer(address indexed from, address indexed to, uint256 value) 954 | func (_Token *TokenFilterer) FilterTransfer(opts *bind.FilterOpts, from []common.Address, to []common.Address) (*TokenTransferIterator, error) { 955 | 956 | var fromRule []interface{} 957 | for _, fromItem := range from { 958 | fromRule = append(fromRule, fromItem) 959 | } 960 | var toRule []interface{} 961 | for _, toItem := range to { 962 | toRule = append(toRule, toItem) 963 | } 964 | 965 | logs, sub, err := _Token.contract.FilterLogs(opts, "Transfer", fromRule, toRule) 966 | if err != nil { 967 | return nil, err 968 | } 969 | return &TokenTransferIterator{contract: _Token.contract, event: "Transfer", logs: logs, sub: sub}, nil 970 | } 971 | 972 | // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. 973 | // 974 | // Solidity: event Transfer(address indexed from, address indexed to, uint256 value) 975 | func (_Token *TokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *TokenTransfer, from []common.Address, to []common.Address) (event.Subscription, error) { 976 | 977 | var fromRule []interface{} 978 | for _, fromItem := range from { 979 | fromRule = append(fromRule, fromItem) 980 | } 981 | var toRule []interface{} 982 | for _, toItem := range to { 983 | toRule = append(toRule, toItem) 984 | } 985 | 986 | logs, sub, err := _Token.contract.WatchLogs(opts, "Transfer", fromRule, toRule) 987 | if err != nil { 988 | return nil, err 989 | } 990 | return event.NewSubscription(func(quit <-chan struct{}) error { 991 | defer sub.Unsubscribe() 992 | for { 993 | select { 994 | case log := <-logs: 995 | // New log arrived, parse the event and forward to the user 996 | event := new(TokenTransfer) 997 | if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { 998 | return err 999 | } 1000 | event.Raw = log 1001 | 1002 | select { 1003 | case sink <- event: 1004 | case err := <-sub.Err(): 1005 | return err 1006 | case <-quit: 1007 | return nil 1008 | } 1009 | case err := <-sub.Err(): 1010 | return err 1011 | case <-quit: 1012 | return nil 1013 | } 1014 | } 1015 | }), nil 1016 | } 1017 | 1018 | // ParseTransfer is a log parse operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. 1019 | // 1020 | // Solidity: event Transfer(address indexed from, address indexed to, uint256 value) 1021 | func (_Token *TokenFilterer) ParseTransfer(log types.Log) (*TokenTransfer, error) { 1022 | event := new(TokenTransfer) 1023 | if err := _Token.contract.UnpackLog(event, "Transfer", log); err != nil { 1024 | return nil, err 1025 | } 1026 | return event, nil 1027 | } 1028 | -------------------------------------------------------------------------------- /contracts/BEP20Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./IBEP20.sol"; 4 | import "./Context.sol"; 5 | import "./SafeMath.sol"; 6 | import "./Ownable.sol"; 7 | 8 | contract BEP20Token is Context, IBEP20, Ownable { 9 | using SafeMath for uint256; 10 | 11 | mapping(address => uint256) private _balances; 12 | mapping(address => mapping(address => uint256)) private _allowances; 13 | uint256 private _totalSupply; 14 | string private _name; 15 | string private _symbol; 16 | uint8 private _decimals; 17 | bool private _mintable; 18 | 19 | /** 20 | * @dev sets initials supply and the owner 21 | */ 22 | function _initialize( 23 | string memory name, 24 | string memory symbol, 25 | uint8 decimals, 26 | uint256 amount, 27 | bool mintable 28 | ) internal { 29 | _name = name; 30 | _symbol = symbol; 31 | _decimals = decimals; 32 | _mintable = mintable; 33 | _mint(owner(), amount); 34 | } 35 | 36 | /** 37 | * @dev Returns if the token is mintable or not 38 | */ 39 | function mintable() external view returns (bool) { 40 | return _mintable; 41 | } 42 | 43 | /** 44 | * @dev Returns the token decimals. 45 | */ 46 | function decimals() external view returns (uint8) { 47 | return _decimals; 48 | } 49 | 50 | /** 51 | * @dev Returns the token symbol. 52 | */ 53 | function symbol() external view returns (string memory) { 54 | return _symbol; 55 | } 56 | 57 | /** 58 | * @dev Returns the token name. 59 | */ 60 | function name() external view returns (string memory) { 61 | return _name; 62 | } 63 | 64 | /** 65 | * @dev Returns the bep token owner. 66 | */ 67 | 68 | function getOwner() external view returns (address) { 69 | return owner(); 70 | } 71 | 72 | /** 73 | * @dev See {BEP20-totalSupply}. 74 | */ 75 | function totalSupply() external view returns (uint256) { 76 | return _totalSupply; 77 | } 78 | 79 | /** 80 | * @dev See {BEP20-balanceOf}. 81 | */ 82 | function balanceOf(address account) external view returns (uint256) { 83 | return _balances[account]; 84 | } 85 | 86 | /** 87 | * @dev See {BEP20-transfer}. 88 | * 89 | * Requirements: 90 | * 91 | * - `recipient` cannot be the zero address. 92 | * - the caller must have a balance of at least `amount`. 93 | */ 94 | function transfer(address recipient, uint256 amount) 95 | external 96 | returns (bool) 97 | { 98 | _transfer(_msgSender(), recipient, amount); 99 | return true; 100 | } 101 | 102 | /** 103 | * @dev See {BEP20-allowance}. 104 | */ 105 | function allowance(address owner, address spender) 106 | external 107 | view 108 | returns (uint256) 109 | { 110 | return _allowances[owner][spender]; 111 | } 112 | 113 | /** 114 | * @dev See {BEP20-approve}. 115 | * 116 | * Requirements: 117 | * 118 | * - `spender` cannot be the zero address. 119 | */ 120 | function approve(address spender, uint256 amount) external returns (bool) { 121 | _approve(_msgSender(), spender, amount); 122 | return true; 123 | } 124 | 125 | /** 126 | * @dev See {BEP20-transferFrom}. 127 | * 128 | * Emits an {Approval} event indicating the updated allowance. This is not 129 | * required by the EIP. See the note at the beginning of {BEP20}; 130 | * 131 | * Requirements: 132 | * - `sender` and `recipient` cannot be the zero address. 133 | * - `sender` must have a balance of at least `amount`. 134 | * - the caller must have allowance for `sender`'s tokens of at least 135 | * `amount`. 136 | */ 137 | function transferFrom( 138 | address sender, 139 | address recipient, 140 | uint256 amount 141 | ) external returns (bool) { 142 | _transfer(sender, recipient, amount); 143 | _approve( 144 | sender, 145 | _msgSender(), 146 | _allowances[sender][_msgSender()].sub( 147 | amount, 148 | "BEP20: transfer amount exceeds allowance" 149 | ) 150 | ); 151 | return true; 152 | } 153 | 154 | /** 155 | * @dev Atomically increases the allowance granted to `spender` by the caller. 156 | * 157 | * This is an alternative to {approve} that can be used as a mitigation for 158 | * problems described in {BEP20-approve}. 159 | * 160 | * Emits an {Approval} event indicating the updated allowance. 161 | * 162 | * Requirements: 163 | * 164 | * - `spender` cannot be the zero address. 165 | */ 166 | function increaseAllowance(address spender, uint256 addedValue) 167 | public 168 | returns (bool) 169 | { 170 | _approve( 171 | _msgSender(), 172 | spender, 173 | _allowances[_msgSender()][spender].add(addedValue) 174 | ); 175 | return true; 176 | } 177 | 178 | /** 179 | * @dev Atomically decreases the allowance granted to `spender` by the caller. 180 | * 181 | * This is an alternative to {approve} that can be used as a mitigation for 182 | * problems described in {BEP20-approve}. 183 | * 184 | * Emits an {Approval} event indicating the updated allowance. 185 | * 186 | * Requirements: 187 | * 188 | * - `spender` cannot be the zero address. 189 | * - `spender` must have allowance for the caller of at least 190 | * `subtractedValue`. 191 | */ 192 | function decreaseAllowance(address spender, uint256 subtractedValue) 193 | public 194 | returns (bool) 195 | { 196 | _approve( 197 | _msgSender(), 198 | spender, 199 | _allowances[_msgSender()][spender].sub( 200 | subtractedValue, 201 | "BEP20: decreased allowance below zero" 202 | ) 203 | ); 204 | return true; 205 | } 206 | 207 | /** 208 | * @dev Creates `amount` tokens and assigns them to `msg.sender`, increasing 209 | * the total supply. 210 | * 211 | * Requirements 212 | * 213 | * - `msg.sender` must be the token owner 214 | * - `_mintable` must be true 215 | */ 216 | function mint(uint256 amount) public onlyOwner returns (bool) { 217 | require(_mintable, "this token is not mintable"); 218 | _mint(_msgSender(), amount); 219 | return true; 220 | } 221 | 222 | /** 223 | * @dev Burn `amount` tokens and decreasing the total supply. 224 | */ 225 | function burn(uint256 amount) public returns (bool) { 226 | _burn(_msgSender(), amount); 227 | return true; 228 | } 229 | 230 | /** 231 | * @dev Moves tokens `amount` from `sender` to `recipient`. 232 | * 233 | * This is internal function is equivalent to {transfer}, and can be used to 234 | * e.g. implement automatic token fees, slashing mechanisms, etc. 235 | * 236 | * Emits a {Transfer} event. 237 | * 238 | * Requirements: 239 | * 240 | * - `sender` cannot be the zero address. 241 | * - `recipient` cannot be the zero address. 242 | * - `sender` must have a balance of at least `amount`. 243 | */ 244 | function _transfer( 245 | address sender, 246 | address recipient, 247 | uint256 amount 248 | ) internal { 249 | require(sender != address(0), "BEP20: transfer from the zero address"); 250 | require(recipient != address(0), "BEP20: transfer to the zero address"); 251 | 252 | _balances[sender] = _balances[sender].sub( 253 | amount, 254 | "BEP20: transfer amount exceeds balance" 255 | ); 256 | _balances[recipient] = _balances[recipient].add(amount); 257 | emit Transfer(sender, recipient, amount); 258 | } 259 | 260 | /** @dev Creates `amount` tokens and assigns them to `account`, increasing 261 | * the total supply. 262 | * 263 | * Emits a {Transfer} event with `from` set to the zero address. 264 | * 265 | * Requirements 266 | * 267 | * - `to` cannot be the zero address. 268 | */ 269 | function _mint(address account, uint256 amount) internal { 270 | require(account != address(0), "BEP20: mint to the zero address"); 271 | 272 | _totalSupply = _totalSupply.add(amount); 273 | _balances[account] = _balances[account].add(amount); 274 | emit Transfer(address(0), account, amount); 275 | } 276 | 277 | /** 278 | * @dev Destroys `amount` tokens from `account`, reducing the 279 | * total supply. 280 | * 281 | * Emits a {Transfer} event with `to` set to the zero address. 282 | * 283 | * Requirements 284 | * 285 | * - `account` cannot be the zero address. 286 | * - `account` must have at least `amount` tokens. 287 | */ 288 | function _burn(address account, uint256 amount) internal { 289 | require(account != address(0), "BEP20: burn from the zero address"); 290 | 291 | _balances[account] = _balances[account].sub( 292 | amount, 293 | "BEP20: burn amount exceeds balance" 294 | ); 295 | _totalSupply = _totalSupply.sub(amount); 296 | emit Transfer(account, address(0), amount); 297 | } 298 | 299 | /** 300 | * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. 301 | * 302 | * This is internal function is equivalent to `approve`, and can be used to 303 | * e.g. set automatic allowances for certain subsystems, etc. 304 | * 305 | * Emits an {Approval} event. 306 | * 307 | * Requirements: 308 | * 309 | * - `owner` cannot be the zero address. 310 | * - `spender` cannot be the zero address. 311 | */ 312 | function _approve( 313 | address owner, 314 | address spender, 315 | uint256 amount 316 | ) internal { 317 | require(owner != address(0), "BEP20: approve from the zero address"); 318 | require(spender != address(0), "BEP20: approve to the zero address"); 319 | 320 | _allowances[owner][spender] = amount; 321 | emit Approval(owner, spender, amount); 322 | } 323 | 324 | /** 325 | * @dev Destroys `amount` tokens from `account`.`amount` is then deducted 326 | * from the caller's allowance. 327 | * 328 | * See {_burn} and {_approve}. 329 | */ 330 | function _burnFrom(address account, uint256 amount) internal { 331 | _burn(account, amount); 332 | _approve( 333 | account, 334 | _msgSender(), 335 | _allowances[account][_msgSender()].sub( 336 | amount, 337 | "BEP20: burn amount exceeds allowance" 338 | ) 339 | ); 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /contracts/Context.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | /* 4 | * @dev Provides information about the current execution context, including the 5 | * sender of the transaction and its data. While these are generally available 6 | * via msg.sender and msg.data, they should not be accessed in such a direct 7 | * manner, since when dealing with GSN meta-transactions the account sending and 8 | * paying for execution may not be the actual sender (as far as an application 9 | * is concerned). 10 | * 11 | * This contract is only required for intermediate, library-like contracts. 12 | */ 13 | contract Context { 14 | // Empty internal constructor, to prevent people from mistakenly deploying 15 | // an instance of this contract, which should be used via inheritance. 16 | constructor() internal {} 17 | 18 | function _msgSender() internal view returns (address payable) { 19 | return msg.sender; 20 | } 21 | 22 | function _msgData() internal view returns (bytes memory) { 23 | this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 24 | return msg.data; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/IBEP20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | interface IBEP20 { 4 | /** 5 | * @dev Returns the amount of tokens in existence. 6 | */ 7 | function totalSupply() external view returns (uint256); 8 | 9 | /** 10 | * @dev Returns the token decimals. 11 | */ 12 | function decimals() external view returns (uint8); 13 | 14 | /** 15 | * @dev Returns the token symbol. 16 | */ 17 | function symbol() external view returns (string memory); 18 | 19 | /** 20 | * @dev Returns the token name. 21 | */ 22 | function name() external view returns (string memory); 23 | 24 | /** 25 | * @dev Returns the bep token owner. 26 | */ 27 | function getOwner() external view returns (address); 28 | 29 | /** 30 | * @dev Returns the amount of tokens owned by `account`. 31 | */ 32 | function balanceOf(address account) external view returns (uint256); 33 | 34 | /** 35 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 36 | * 37 | * Returns a boolean value indicating whether the operation succeeded. 38 | * 39 | * Emits a {Transfer} event. 40 | */ 41 | function transfer(address recipient, uint256 amount) 42 | external 43 | returns (bool); 44 | 45 | /** 46 | * @dev Returns the remaining number of tokens that `spender` will be 47 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 48 | * zero by default. 49 | * 50 | * This value changes when {approve} or {transferFrom} are called. 51 | */ 52 | function allowance(address _owner, address spender) 53 | external 54 | view 55 | returns (uint256); 56 | 57 | /** 58 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 59 | * 60 | * Returns a boolean value indicating whether the operation succeeded. 61 | * 62 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 63 | * that someone may use both the old and the new allowance by unfortunate 64 | * transaction ordering. One possible solution to mitigate this race 65 | * condition is to first reduce the spender's allowance to 0 and set the 66 | * desired value afterwards: 67 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 68 | * 69 | * Emits an {Approval} event. 70 | */ 71 | function approve(address spender, uint256 amount) external returns (bool); 72 | 73 | /** 74 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 75 | * allowance mechanism. `amount` is then deducted from the caller's 76 | * allowance. 77 | * 78 | * Returns a boolean value indicating whether the operation succeeded. 79 | * 80 | * Emits a {Transfer} event. 81 | */ 82 | function transferFrom( 83 | address sender, 84 | address recipient, 85 | uint256 amount 86 | ) external returns (bool); 87 | 88 | /** 89 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 90 | * another (`to`). 91 | * 92 | * Note that `value` may be zero. 93 | */ 94 | event Transfer(address indexed from, address indexed to, uint256 value); 95 | 96 | /** 97 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 98 | * a call to {approve}. `value` is the new allowance. 99 | */ 100 | event Approval( 101 | address indexed owner, 102 | address indexed spender, 103 | uint256 value 104 | ); 105 | } 106 | -------------------------------------------------------------------------------- /contracts/IERC900.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | /** 4 | * @title ERC900 Simple Staking Interface 5 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-900.md 6 | */ 7 | 8 | contract IERC900 { 9 | event Staked( 10 | address indexed user, 11 | uint256 amount, 12 | uint256 total, 13 | bytes data 14 | ); 15 | event Unstaked( 16 | address indexed user, 17 | uint256 amount, 18 | uint256 total, 19 | bytes data 20 | ); 21 | 22 | function stake(uint256 amount, bytes memory data) public; 23 | 24 | function stakeFor( 25 | address user, 26 | uint256 amount, 27 | bytes memory data 28 | ) public; 29 | 30 | function unstake(uint256 amount, bytes memory data) public; 31 | 32 | function totalStakedFor(address addr) public view returns (uint256); 33 | 34 | function totalStaked() public view returns (uint256); 35 | 36 | function token() public view returns (address); 37 | 38 | function supportsHistory() public pure returns (bool); 39 | } 40 | -------------------------------------------------------------------------------- /contracts/ITokenHub.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | contract ITokenHub { 4 | function transferOut( 5 | address contractAddr, 6 | address recipient, 7 | uint256 amount, 8 | uint64 expireTime 9 | ) external payable returns (bool); 10 | } 11 | -------------------------------------------------------------------------------- /contracts/ITokenManager.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | contract ITokenManager { 4 | function approveBind(address contractAddr, string memory bep2Symbol) 5 | public 6 | payable 7 | returns (bool); 8 | } 9 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.8.0; 3 | 4 | contract Migrations { 5 | address public owner = msg.sender; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | require( 10 | msg.sender == owner, 11 | "This function is restricted to the contract's owner" 12 | ); 13 | _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /contracts/MultiSendWallet.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./IBEP20.sol"; 4 | import "./Ownable.sol"; 5 | import "./SafeMath.sol"; 6 | 7 | // Gas cost = 553591 => 820814 gas for deploying (0.03875137 => 0.05745698 ETH at 70Gwei) 8 | contract MultiSendWallet is Ownable { 9 | using SafeMath for uint256; 10 | 11 | constructor(address _owner) public { 12 | _transferOwnership(_owner); 13 | } 14 | 15 | function multiTransferERC20TightlyPacked( 16 | address _token, 17 | bytes32[] memory _addressesAndAmounts, 18 | uint8 _inputDecimals 19 | ) public onlyOwner returns (bool) { 20 | require(_token != address(0)); 21 | for (uint256 i = 0; i < _addressesAndAmounts.length; i++) { 22 | IBEP20 token = IBEP20(_token); 23 | address to = address(uint160(uint256(_addressesAndAmounts[i]))); 24 | uint8 boost = token.decimals() - _inputDecimals; 25 | require(boost >= 0, "boost should be >= 0"); 26 | uint256 amount; 27 | if (boost == uint8(0)) { 28 | amount = uint256(uint96(bytes12(_addressesAndAmounts[i]))); 29 | } else { 30 | amount = uint256(uint96(bytes12(_addressesAndAmounts[i]))).mul( 31 | 10**uint256(boost) 32 | ); 33 | } 34 | require(token.transfer(to, amount)); 35 | } 36 | } 37 | 38 | function multiTransferERC20( 39 | address token, 40 | address[] memory _contributors, 41 | uint256[] memory _amounts 42 | ) public onlyOwner returns (bool) { 43 | require(_contributors.length == _amounts.length, "length is mismatch"); 44 | for (uint256 i = 0; i < _contributors.length; i++) { 45 | require(IBEP20(token).transfer(_contributors[i], _amounts[i])); 46 | } 47 | } 48 | 49 | // The contract doesn't allow receiving Ether. 50 | function() external { 51 | revert(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/MultiSendWalletFactory.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./MultiSendWallet.sol"; 4 | 5 | contract MultiSendWalletFactory { 6 | event Deployed(address wallet); 7 | 8 | function deployNewWallet(address _owner) public returns (address) { 9 | MultiSendWallet wallet = new MultiSendWallet(_owner); 10 | emit Deployed(address(wallet)); 11 | return address(wallet); 12 | } 13 | 14 | // The contract doesn't allow receiving Ether. 15 | function() external { 16 | revert(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/MultiSendableToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./BEP20Token.sol"; 4 | 5 | contract MultiSendableToken is BEP20Token { 6 | event MultiTransfer( 7 | address indexed _from, 8 | address indexed _to, 9 | uint256 _amount 10 | ); 11 | 12 | constructor() public { 13 | _initialize("TEST token", "TESTONE", 18, 1 * 10**9 * 10**18, false); 14 | } 15 | 16 | function multiTransferTightlyPacked( 17 | bytes32[] memory _addressesAndAmounts, 18 | uint8 _inputDecimals 19 | ) public payable { 20 | for (uint256 i = 0; i < _addressesAndAmounts.length; i++) { 21 | address to = address(uint160(uint256(_addressesAndAmounts[i]))); 22 | uint8 boost = this.decimals() - _inputDecimals; 23 | require(boost >= 0, "boost should be >= 0"); 24 | uint256 amount; 25 | if (boost == uint8(0)) { 26 | amount = uint256(uint96(bytes12(_addressesAndAmounts[i]))); 27 | } else { 28 | amount = uint256(uint96(bytes12(_addressesAndAmounts[i]))).mul( 29 | 10**uint256(boost) 30 | ); 31 | } 32 | _transfer(msg.sender, to, amount); 33 | emit MultiTransfer(msg.sender, to, amount); 34 | } 35 | } 36 | 37 | function multiTransfer( 38 | address[] memory _contributors, 39 | uint256[] memory _amounts 40 | ) public returns (bool) { 41 | require(_contributors.length == _amounts.length, "length is mismatch"); 42 | for (uint256 i = 0; i < _contributors.length; i++) { 43 | _transfer(msg.sender, _contributors[i], _amounts[i]); 44 | emit MultiTransfer(msg.sender, _contributors[i], _amounts[i]); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/Ownable.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./Context.sol"; 4 | /** 5 | * @dev Contract module which provides a basic access control mechanism, where 6 | * there is an account (an owner) that can be granted exclusive access to 7 | * specific functions. 8 | * 9 | * By default, the owner account will be the one that deploys the contract. This 10 | * can later be changed with {transferOwnership}. 11 | * 12 | * This module is used through inheritance. It will make available the modifier 13 | * `onlyOwner`, which can be applied to your functions to restrict their use to 14 | * the owner. 15 | */ 16 | contract Ownable is Context { 17 | address private _owner; 18 | 19 | event OwnershipTransferred( 20 | address indexed previousOwner, 21 | address indexed newOwner 22 | ); 23 | 24 | /** 25 | * @dev Initializes the contract setting the deployer as the initial owner. 26 | */ 27 | constructor() internal { 28 | address msgSender = _msgSender(); 29 | _owner = msgSender; 30 | emit OwnershipTransferred(address(0), msgSender); 31 | } 32 | 33 | /** 34 | * @dev Returns the address of the current owner. 35 | */ 36 | function owner() public view returns (address) { 37 | return _owner; 38 | } 39 | 40 | /** 41 | * @dev Throws if called by any account other than the owner. 42 | */ 43 | modifier onlyOwner() { 44 | require(_owner == _msgSender(), "Ownable: caller is not the owner"); 45 | _; 46 | } 47 | 48 | /** 49 | * @dev Leaves the contract without owner. It will not be possible to call 50 | * `onlyOwner` functions anymore. Can only be called by the current owner. 51 | * 52 | * NOTE: Renouncing ownership will leave the contract without an owner, 53 | * thereby removing any functionality that is only available to the owner. 54 | */ 55 | function renounceOwnership() public onlyOwner { 56 | emit OwnershipTransferred(_owner, address(0)); 57 | _owner = address(0); 58 | } 59 | 60 | /** 61 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 62 | * Can only be called by the current owner. 63 | */ 64 | function transferOwnership(address newOwner) public onlyOwner { 65 | _transferOwnership(newOwner); 66 | } 67 | 68 | /** 69 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 70 | */ 71 | function _transferOwnership(address newOwner) internal { 72 | require( 73 | newOwner != address(0), 74 | "Ownable: new owner is the zero address" 75 | ); 76 | emit OwnershipTransferred(_owner, newOwner); 77 | _owner = newOwner; 78 | } 79 | } -------------------------------------------------------------------------------- /contracts/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | /** 3 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 4 | * checks. 5 | * 6 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 7 | * in bugs, because programmers usually assume that an overflow raises an 8 | * error, which is the standard behavior in high level programming languages. 9 | * `SafeMath` restores this intuition by reverting the transaction when an 10 | * operation overflows. 11 | * 12 | * Using this library instead of the unchecked operations eliminates an entire 13 | * class of bugs, so it's recommended to use it always. 14 | */ 15 | library SafeMath { 16 | /** 17 | * @dev Returns the addition of two unsigned integers, reverting on 18 | * overflow. 19 | * 20 | * Counterpart to Solidity's `+` operator. 21 | * 22 | * Requirements: 23 | * - Addition cannot overflow. 24 | */ 25 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 26 | uint256 c = a + b; 27 | require(c >= a, "SafeMath: addition overflow"); 28 | 29 | return c; 30 | } 31 | 32 | /** 33 | * @dev Returns the subtraction of two unsigned integers, reverting on 34 | * overflow (when the result is negative). 35 | * 36 | * Counterpart to Solidity's `-` operator. 37 | * 38 | * Requirements: 39 | * - Subtraction cannot overflow. 40 | */ 41 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 42 | return sub(a, b, "SafeMath: subtraction overflow"); 43 | } 44 | 45 | /** 46 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 47 | * overflow (when the result is negative). 48 | * 49 | * Counterpart to Solidity's `-` operator. 50 | * 51 | * Requirements: 52 | * - Subtraction cannot overflow. 53 | */ 54 | function sub( 55 | uint256 a, 56 | uint256 b, 57 | string memory errorMessage 58 | ) internal pure returns (uint256) { 59 | require(b <= a, errorMessage); 60 | uint256 c = a - b; 61 | 62 | return c; 63 | } 64 | 65 | /** 66 | * @dev Returns the multiplication of two unsigned integers, reverting on 67 | * overflow. 68 | * 69 | * Counterpart to Solidity's `*` operator. 70 | * 71 | * Requirements: 72 | * - Multiplication cannot overflow. 73 | */ 74 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 75 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 76 | // benefit is lost if 'b' is also tested. 77 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 78 | if (a == 0) { 79 | return 0; 80 | } 81 | 82 | uint256 c = a * b; 83 | require(c / a == b, "SafeMath: multiplication overflow"); 84 | 85 | return c; 86 | } 87 | 88 | /** 89 | * @dev Returns the integer division of two unsigned integers. Reverts on 90 | * division by zero. The result is rounded towards zero. 91 | * 92 | * Counterpart to Solidity's `/` operator. Note: this function uses a 93 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 94 | * uses an invalid opcode to revert (consuming all remaining gas). 95 | * 96 | * Requirements: 97 | * - The divisor cannot be zero. 98 | */ 99 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 100 | return div(a, b, "SafeMath: division by zero"); 101 | } 102 | 103 | /** 104 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 105 | * division by zero. The result is rounded towards zero. 106 | * 107 | * Counterpart to Solidity's `/` operator. Note: this function uses a 108 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 109 | * uses an invalid opcode to revert (consuming all remaining gas). 110 | * 111 | * Requirements: 112 | * - The divisor cannot be zero. 113 | */ 114 | function div( 115 | uint256 a, 116 | uint256 b, 117 | string memory errorMessage 118 | ) internal pure returns (uint256) { 119 | // Solidity only automatically asserts when dividing by 0 120 | require(b > 0, errorMessage); 121 | uint256 c = a / b; 122 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 123 | 124 | return c; 125 | } 126 | 127 | /** 128 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 129 | * Reverts when dividing by zero. 130 | * 131 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 132 | * opcode (which leaves remaining gas untouched) while Solidity uses an 133 | * invalid opcode to revert (consuming all remaining gas). 134 | * 135 | * Requirements: 136 | * - The divisor cannot be zero. 137 | */ 138 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 139 | return mod(a, b, "SafeMath: modulo by zero"); 140 | } 141 | 142 | /** 143 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 144 | * Reverts with custom message when dividing by zero. 145 | * 146 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 147 | * opcode (which leaves remaining gas untouched) while Solidity uses an 148 | * invalid opcode to revert (consuming all remaining gas). 149 | * 150 | * Requirements: 151 | * - The divisor cannot be zero. 152 | */ 153 | function mod( 154 | uint256 a, 155 | uint256 b, 156 | string memory errorMessage 157 | ) internal pure returns (uint256) { 158 | require(b != 0, errorMessage); 159 | return a % b; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /contracts/Staking.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./IBEP20.sol"; 4 | import "./SafeMath.sol"; 5 | import "./IERC900.sol"; 6 | 7 | contract Staking is IERC900 { 8 | using SafeMath for uint256; 9 | // Token used for staking 10 | IBEP20 stakingToken; 11 | 12 | uint256 public index; 13 | mapping(uint256 => Stake) private stakes; 14 | mapping(address => uint256) private stakingFor; 15 | // Set node info 16 | mapping(address => P2PInfo) private nodes; 17 | 18 | struct Stake { 19 | uint256 expiry; 20 | uint256 amount; 21 | address stakedFor; 22 | } 23 | 24 | struct P2PInfo { 25 | bytes32 pubkey; 26 | bytes32 rewardAddress; 27 | } 28 | 29 | /** 30 | * @dev Modifier that checks that this contract can transfer tokens from the 31 | * balance in the stakingToken contract for the given address. 32 | * @dev This modifier also transfers the tokens. 33 | * @param _address address to transfer tokens from 34 | * @param _amount uint256 the number of tokens 35 | */ 36 | modifier canStake(address _address, uint256 _amount) { 37 | require( 38 | stakingToken.transferFrom(_address, address(this), _amount), 39 | "Stake required" 40 | ); 41 | _; 42 | } 43 | 44 | /** 45 | * @dev Constructor function 46 | * @param _stakingToken ERC20/BEP20 The address of the token contract used for staking 47 | */ 48 | constructor(IBEP20 _stakingToken) public { 49 | stakingToken = _stakingToken; 50 | index = 0; 51 | } 52 | 53 | /** 54 | * @notice Stakes a certain amount of tokens, this MUST transfer the given amount from the user 55 | * @notice MUST trigger Staked event 56 | * @param _amount uint256 the amount of tokens to stake 57 | * @param _data bytes optional data to include in the Stake event 58 | */ 59 | function stake(uint256 _amount, bytes memory _data) public { 60 | _stake(msg.sender, _amount, _data); 61 | } 62 | 63 | /** 64 | * @notice Stakes a certain amount of tokens, this MUST transfer the given amount from the caller 65 | * @notice MUST trigger Staked event 66 | * @param _user address the address the tokens are staked for 67 | * @param _amount uint256 the amount of tokens to stake 68 | * @param _data bytes optional data to include in the Stake event 69 | */ 70 | function stakeFor( 71 | address _user, 72 | uint256 _amount, 73 | bytes memory _data 74 | ) public { 75 | _stake(_user, _amount, _data); 76 | } 77 | 78 | /** 79 | * @notice Unstakes a certain amount of tokens, this SHOULD return the given amount of tokens to the user, if unstaking is currently not possible the function MUST revert 80 | * @notice MUST trigger Unstaked event 81 | * @param _amount uint256 the amount of tokens to unstake 82 | * @param _data bytes optional data to include in the Unstake event 83 | */ 84 | function unstake(uint256 _amount, bytes memory _data) public { 85 | _unstake(msg.sender, _amount, _data); 86 | } 87 | 88 | /** 89 | * @notice Returns the current total of tokens staked for an address 90 | * @param _address address The address to query 91 | * @return uint256 The number of tokens staked for the given address 92 | */ 93 | function totalStakedFor(address _address) public view returns (uint256) { 94 | return stakingFor[_address]; 95 | } 96 | 97 | /** 98 | * @notice Returns the current total of tokens staked 99 | * @return uint256 The number of tokens staked in the contract 100 | */ 101 | function totalStaked() public view returns (uint256) { 102 | return stakingToken.balanceOf(address(this)); 103 | } 104 | 105 | /** 106 | * @notice Address of the token being used by the staking interface 107 | * @return address The address of the ERC20 token used for staking 108 | */ 109 | function token() public view returns (address) { 110 | return address(stakingToken); 111 | } 112 | 113 | function supportsHistory() public pure returns (bool) { 114 | return false; 115 | } 116 | 117 | /** 118 | @TODO: add getter for each stakes like function getStake(uint256 stakeID) 119 | */ 120 | 121 | /** 122 | * @param _addr The address of validator set 123 | */ 124 | function getNodeInfo(address _addr) public view returns (bytes32, bytes32) { 125 | P2PInfo memory info = nodes[_addr]; 126 | return (info.pubkey, info.rewardAddress); 127 | } 128 | 129 | /** 130 | * @dev Helper function to create stakes for a given address 131 | * @param _address address The address the stake is being created for 132 | * @param _amount uint256 The number of tokens being staked 133 | * @param _data bytes optional data to include in the Stake event. We are using for locktime period for each stake. 134 | */ 135 | function _stake( 136 | address _address, 137 | uint256 _amount, 138 | bytes memory _data 139 | ) internal canStake(_address, _amount) { 140 | (uint256 expiry, bytes32 pubkey, bytes32 rewardAddress) = decodeBytes( 141 | _data 142 | ); 143 | // TODO: validate timestamp 144 | stakes[index] = Stake(expiry, _amount, _address); 145 | stakingFor[_address] = stakingFor[_address].add(_amount); 146 | 147 | // Update node info 148 | nodes[_address] = P2PInfo(pubkey, rewardAddress); 149 | 150 | // Staked event. the logger needs to decode event to time on client side. 151 | // Data == 0x + index + _data 152 | emit Staked( 153 | _address, 154 | _amount, 155 | totalStakedFor(_address), 156 | joinLogData(index, _data) 157 | ); 158 | index++; 159 | } 160 | 161 | function _unstake( 162 | address _address, 163 | uint256 _amount, 164 | bytes memory _data 165 | ) internal { 166 | (uint256 stakeID, , ) = decodeBytes(_data); 167 | Stake memory target = stakes[stakeID]; 168 | // The target amount should be same as input amount. 169 | require( 170 | target.amount == _amount, 171 | "The unstake amount does not match the target amount" 172 | ); 173 | require( 174 | target.stakedFor == _address, 175 | "The address does not match the target address" 176 | ); 177 | require( 178 | block.timestamp >= target.expiry, 179 | "The target stake is not expired" 180 | ); 181 | require( 182 | stakingToken.transfer(target.stakedFor, _amount), 183 | "Unable to withdraw stake" 184 | ); 185 | // Reduced staking amount of current staker. 186 | stakingFor[target.stakedFor] = stakingFor[target.stakedFor].sub( 187 | _amount 188 | ); 189 | // Removed a stake and gas is refunded. 190 | delete (stakes[stakeID]); 191 | // Unstaked event. the logger needs to decode event to time on client side. 192 | // Data == 0x + stakeID 193 | emit Unstaked( 194 | target.stakedFor, 195 | _amount, 196 | totalStakedFor(target.stakedFor), 197 | _data 198 | ); 199 | } 200 | 201 | function joinLogData(uint256 stakeID, bytes memory data) 202 | internal 203 | pure 204 | returns (bytes memory) 205 | { 206 | return abi.encodePacked(stakeID, data); 207 | } 208 | 209 | function decodeBytes(bytes memory _data) 210 | internal 211 | pure 212 | returns ( 213 | uint256, 214 | bytes32, 215 | bytes32 216 | ) 217 | { 218 | require(_data.length.mod(32) == 0, "slicing out of range"); 219 | uint256 expiry; 220 | bytes32 pubkey; 221 | bytes32 rewardAddress; 222 | assembly { 223 | expiry := mload(add(_data, 32)) 224 | pubkey := mload(add(_data, 64)) 225 | rewardAddress := mload(add(_data, 96)) 226 | } 227 | return (expiry, pubkey, rewardAddress); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /contracts/Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./BEP20Token.sol"; 4 | 5 | contract Token is BEP20Token { 6 | constructor() public { 7 | _initialize("SWINGBY token", "SWINGBY", 18, 1 * 10**9 * 10**18, false); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /contracts/TokenMultiSendWrapper.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.5.16; 2 | 3 | import "./MultiSendableToken.sol"; 4 | import "./IBEP20.sol"; 5 | 6 | contract TokenMultiSendWrapper is MultiSendableToken { 7 | event Deposit(address indexed _from, address indexed _to, uint256 _amount); 8 | event Withdraw(address indexed _from, address indexed _to, uint256 _amount); 9 | // Define token address for wrapping. 10 | IBEP20 public token; 11 | 12 | function deposit(uint256 _amount) public returns (bool) { 13 | require( 14 | token.transferFrom(msg.sender, address(this), _amount), 15 | "deposit error" 16 | ); 17 | _mint(msg.sender, _amount); 18 | emit Deposit(msg.sender, address(this), _amount); 19 | return true; 20 | } 21 | 22 | function withdraw(uint256 _amount) public returns (bool) { 23 | _burn(msg.sender, _amount); 24 | require(token.transfer(msg.sender, _amount), "withdraw error"); 25 | emit Withdraw(address(this), msg.sender, _amount); 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function (deployer, net, acc) { 4 | //console.log(acc[0]) 5 | if (net !== "development") { 6 | return 7 | } 8 | //deployer.deploy(Migrations); 9 | }; 10 | -------------------------------------------------------------------------------- /migrations/2_deploy_token.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require("Token"); 2 | 3 | module.exports = function (deployer) { 4 | deployer.deploy(Token); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bep20token", 3 | "version": "1.0.0", 4 | "description": "## Requrements - truffle v5.1.43 (Solidity v0.5.16 (solc-js), Node v14.8.0, Web3.js v1.2.1) - ganache test rpc.", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": { 10 | "@truffle/hdwallet-provider": "^1.1.1", 11 | "bech32-buffer": "^0.1.2", 12 | "web3": "^1.3.0" 13 | }, 14 | "devDependencies": {}, 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/SwingbyProtocol/BEP20Token.git" 21 | }, 22 | "author": "", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/SwingbyProtocol/BEP20Token/issues" 26 | }, 27 | "homepage": "https://github.com/SwingbyProtocol/BEP20Token#readme" 28 | } 29 | -------------------------------------------------------------------------------- /scripts/approveTokens.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require("Token"); 2 | // The Address of token manager contract 3 | const tokenManagerConctractAddr = "0x0000000000000000000000000000000000001008" 4 | const BN = web3.utils.BN; 5 | 6 | module.exports = async function (done) { 7 | try { 8 | const token = await Token.deployed() 9 | let amount = web3.utils.toWei(new BN(process.env.AMOUNT).mul(new BN(1 * 10 ** 10)), 'wei') 10 | let result = await token.approve(tokenManagerConctractAddr, amount) 11 | console.log(result.tx) 12 | done() 13 | } catch (err) { 14 | console.log(err) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /scripts/bindTokenContract.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require("Token"); 2 | const tokenManager = artifacts.require("ITokenManager"); 3 | // The Address of token manager 4 | const tokenManagerConctractAddr = "0x0000000000000000000000000000000000001008" 5 | const BN = web3.utils.BN; 6 | 7 | module.exports = async function (done) { 8 | try { 9 | const token = await Token.deployed() 10 | const tm = await tokenManager.at(tokenManagerConctractAddr) 11 | minRelayFee = "0.01" 12 | let value = web3.utils.toWei(minRelayFee, 'ether') 13 | let result = await tm.approveBind(token.address, process.env.SYMBOL, { 14 | value: value 15 | }) 16 | console.log(result.tx) 17 | done() 18 | } catch (err) { 19 | console.log(err) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scripts/exportABIs.js: -------------------------------------------------------------------------------- 1 | const BEP20Token = artifacts.require("BEP20Token"); 2 | const Staking = artifacts.require("Staking"); 3 | fs = require('fs'); 4 | 5 | module.exports = async function () { 6 | try { 7 | const token = await BEP20Token.deployed() 8 | path = "./abi/token.abi" 9 | await exportFile(path, token.abi) 10 | //const stake = await Staking.deployed() 11 | //console.log(stake.abi) 12 | } catch (err) { 13 | console.log(err) 14 | } 15 | } 16 | 17 | 18 | function exportFile(name, obj) { 19 | let data = JSON.stringify(obj) 20 | return new Promise((resolve, reject) => { 21 | fs.writeFile(name, data, function (err) { 22 | if (err) return reject(err) 23 | console.log("Abi file exported => ", name) 24 | resolve() 25 | }); 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /scripts/transfer.js: -------------------------------------------------------------------------------- 1 | const BEP20Token = artifacts.require("BEP20Token"); 2 | // The Address of token manager contract 3 | const BN = web3.utils.BN; 4 | 5 | module.exports = async function () { 6 | try { 7 | const token = await BEP20Token.deployed() 8 | let amount = web3.utils.toWei(new BN('1000'), 'ether') 9 | await token.transfer(process.env.TO, amount) 10 | } catch (err) { 11 | console.log(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /scripts/transferOutToBC.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require("Token"); 2 | const ITokenHub = artifacts.require("ITokenHub"); 3 | // The Address of token manager 4 | const tokenHubConctractAddr = "0x0000000000000000000000000000000000001004" 5 | const BN = web3.utils.BN; 6 | const bech32 = require('bech32-buffer'); 7 | 8 | module.exports = async function (done) { 9 | try { 10 | const token = await Token.deployed() 11 | const th = await ITokenHub.at(tokenHubConctractAddr) 12 | minRelayFee = "0.01" 13 | let value = web3.utils.toWei(minRelayFee, 'ether') 14 | let amount = web3.utils.toWei(process.env.AMOUNT, 'ether') 15 | let addr = bech32.decode(process.env.TO) 16 | let to = "0x" + Buffer.from(addr.data).toString('hex') 17 | let time = Math.floor(Date.now() / 1000) + 1000 18 | let approve = await token.approve(th.address, amount) 19 | console.log(approve.tx, "approved") 20 | let result = await th.transferOut(token.address, to, amount, time, { 21 | value: value 22 | }) 23 | console.log(result.tx, "done") 24 | done() 25 | } catch (err) { 26 | console.log(err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/stakeTest.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require('Token'); 2 | const Staking = artifacts.require('Staking'); 3 | 4 | const BN = web3.utils.BN; 5 | 6 | contract('Staking', async (accounts) => { 7 | it('Token issue and Staking test', async () => { 8 | try { 9 | let token = await Token.new() 10 | let mintValue = web3.utils.toWei(new BN('1000000000'), 'ether') 11 | let from = accounts[0]; 12 | let to = accounts[1]; 13 | let amount = web3.utils.toWei(new BN('20'), 'ether') 14 | 15 | let balanceFrom = await token.balanceOf(from); 16 | 17 | assert.equal(balanceFrom.toString(), mintValue.toString()); 18 | 19 | let balanceTo = await token.balanceOf(to); 20 | await token.transfer(to, amount, { 21 | from: from 22 | }); 23 | 24 | let updateBalanceFrom = await token.balanceOf(from); 25 | let updateBalanceTo = await token.balanceOf(to); 26 | 27 | assert.equal(mintValue.sub(amount).toString(), updateBalanceFrom.toString()); 28 | assert.equal(balanceTo.add(amount).toString(), updateBalanceTo.toString()); 29 | 30 | let stake = await Staking.new(token.address) 31 | let amountToStake = web3.utils.toWei(new BN('10000'), 'ether') 32 | 33 | await token.approve(stake.address, amountToStake, { 34 | from: from 35 | }); 36 | let timeHex = web3.utils.toHex(Math.floor(Date.now() / 1000)) 37 | let timeHex32 = web3.utils.padLeft(timeHex, 64) 38 | let pubkeyHex32 = web3.utils.padLeft("0xc4b50e91d77878cefcb8467694503c5f9a74d49b0077316f327786c3abdfdc75", 64) 39 | let addressHex32 = web3.utils.padLeft(accounts[1], 64) 40 | let data = timeHex32 + pubkeyHex32.slice(2) + addressHex32.slice(2) 41 | // 0x000000000000000000000000000000000000000000000000000000005f846a50c4b50e91d77878cefcb8467694503c5f9a74d49b0077316f327786c3abdfdc75000000000000000000000000943Bef1Fb2F25C43Ab4a010ae835E936d1A34fE1 42 | 43 | //console.log(data) 44 | 45 | await stake.stake(amountToStake, data, { from: from }) 46 | 47 | let nodeInfo = await stake.getNodeInfo(from) 48 | /** 49 | * Result { '0': '0xc4b50e91d77878cefcb8467694503c5f9a74d49b0077316f327786c3abdfdc75', '1': '0x00000000000000000000000007385da2f4ebe2d2a6f837f3719952ea580301f5'} 50 | */ 51 | 52 | //console.log(nodeInfo) 53 | let StakedBalance = await stake.totalStakedFor(from); 54 | assert.equal(amountToStake.toString(), StakedBalance.toString()); 55 | 56 | let stakeID = web3.utils.padLeft("0x0", 64) 57 | await stake.unstake(amountToStake, stakeID, { from: from }) 58 | 59 | let NewStakedBalance = await stake.totalStakedFor(from); 60 | assert.equal(NewStakedBalance.toString(), "0"); 61 | 62 | } catch (err) { 63 | console.log(err) 64 | } 65 | }); 66 | }) -------------------------------------------------------------------------------- /test/tokenTest.js: -------------------------------------------------------------------------------- 1 | const Token = artifacts.require('Token'); 2 | const MultiSendableToken = artifacts.require("MultiSendableToken") 3 | const BN = web3.utils.BN; 4 | 5 | contract('Token', async (accounts) => { 6 | it('transfer', async () => { 7 | let token = await Token.new() 8 | let mintValue = web3.utils.toWei(new BN('1000000000'), 'ether') 9 | let from = accounts[0]; 10 | let to = accounts[1]; 11 | let amount = web3.utils.toWei(new BN('20'), 'ether') 12 | 13 | let balanceFrom = await token.balanceOf(from); 14 | 15 | assert.equal(balanceFrom.toString(), mintValue.toString()); 16 | 17 | let balanceTo = await token.balanceOf(to); 18 | 19 | await token.transfer(to, amount, { 20 | from: from 21 | }); 22 | 23 | let updateBalanceFrom = await token.balanceOf(from); 24 | let updateBalanceTo = await token.balanceOf(to); 25 | 26 | assert.equal(mintValue.sub(amount).toString(), updateBalanceFrom.toString()); 27 | assert.equal(balanceTo.add(amount).toString(), updateBalanceTo.toString()); 28 | }); 29 | 30 | it('multi transfer', async () => { 31 | let token = await MultiSendableToken.new() 32 | let mintValue = web3.utils.toWei(new BN('1000000000'), 'ether') 33 | let from = accounts[0]; 34 | let to = accounts[1]; 35 | let to2 = accounts[2] 36 | let amount = web3.utils.toWei(new BN('500000000'), 'ether') 37 | 38 | let balanceFrom = await token.balanceOf(from); 39 | 40 | assert.equal(balanceFrom.toString(), mintValue.toString()); 41 | 42 | let balanceTo = await token.balanceOf(to); 43 | 44 | let send1 = "0x" + web3.utils.padLeft(amount.toString('hex') + to.slice(2), 64) 45 | 46 | let send2 = "0x" + web3.utils.padLeft(amount.toString('hex') + to2.slice(2), 64) 47 | // 0x00000001158e460913d00000943Bef1Fb2F25C43Ab4a010ae835E936d1A34fE1 48 | 49 | // console.log(send1) 50 | 51 | const txs = [ 52 | send1, send2 53 | ] 54 | 55 | // Should be 32bytes hex if calling from golang 56 | const inputDecimals = 18 57 | 58 | let logs = await token.multiTransferTightlyPacked(txs, inputDecimals, { 59 | from: from 60 | }); 61 | 62 | // console.log(logs.logs) 63 | 64 | let updateBalanceFrom = await token.balanceOf(from); 65 | let updateBalanceTo = await token.balanceOf(to); 66 | let updateBalanceTo2 = await token.balanceOf(to2); 67 | 68 | 69 | assert.equal(mintValue.sub(amount).sub(amount).toString(), updateBalanceFrom.toString()); 70 | assert.equal(balanceTo.add(amount).toString(), updateBalanceTo.toString()); 71 | assert.equal(amount.toString(), updateBalanceTo2.toString()); 72 | 73 | }); 74 | // it('Contract paused', async () => { 75 | // let decimals = 18 76 | // let mintValue = web3.utils.toWei(new BN('1000000000'), 'ether') 77 | // let token = await Token.new() 78 | 79 | // let from = accounts[0]; 80 | 81 | // let balanceFrom = await token.balanceOf(from); 82 | 83 | // assert.equal(balanceFrom.toString(), mintValue.toString()); 84 | 85 | // await token.setPaused(true) 86 | 87 | // let to = accounts[1]; 88 | // let amount = web3.utils.toWei(new BN('20'), 'ether') 89 | 90 | // await token.transfer(to, amount, { 91 | // from: from 92 | // }).catch((err) => { 93 | // assert.isObject(err, "passed") 94 | // }); 95 | 96 | // await token.approve(to, amount, { 97 | // from: from 98 | // }).catch((err) => { 99 | // assert.isObject(err, "passed") 100 | // }); 101 | 102 | // await token.increaseAllowance(to, amount, { 103 | // from: from 104 | // }).catch((err) => { 105 | // assert.isObject(err, "passed") 106 | // }); 107 | // await token.decreaseAllowance(to, amount, { 108 | // from: from 109 | // }).catch((err) => { 110 | // assert.isObject(err, "passed") 111 | // }); 112 | 113 | // await token.mint(to, amount, { 114 | // from: from 115 | // }).catch((err) => { 116 | // assert.isObject(err, "passed") 117 | // }); 118 | // }) 119 | // it('token mint', async () => { 120 | // let token = await Token.new() 121 | // let mintValue = web3.utils.toWei(new BN('1000000000'), 'ether') 122 | // let from = accounts[0]; 123 | // let amount = web3.utils.toWei(new BN('20'), 'ether') 124 | 125 | // let balanceFrom = await token.balanceOf(from); 126 | 127 | // assert.equal(balanceFrom.toString(), mintValue.toString()); 128 | 129 | // await token.mint(amount, { 130 | // from: from 131 | // }) 132 | 133 | // await token.mint(amount, { 134 | // from: accounts[2] 135 | // }).catch((err) => { 136 | // assert.notEqual(err, null) 137 | // }); 138 | 139 | // let updateBalanceFrom = await token.balanceOf(from); 140 | 141 | // assert.equal(balanceFrom.add(amount).toString(), updateBalanceFrom.toString()); 142 | // }); 143 | }) -------------------------------------------------------------------------------- /test/walletTest.js: -------------------------------------------------------------------------------- 1 | const MultiSendWallet = artifacts.require('MultiSendWallet'); 2 | const Token = artifacts.require('Token'); 3 | const MultiSendWalletFactory = artifacts.require("MultiSendWalletFactory") 4 | 5 | const BN = web3.utils.BN; 6 | 7 | contract('MultiSendWallet', async (accounts) => { 8 | it('Token deploy and checking the owner', async () => { 9 | try { 10 | let from = accounts[1]; 11 | let wallet = await MultiSendWallet.new(from) 12 | let owner = await wallet.owner() 13 | assert.equal(owner, from); 14 | } catch (err) { 15 | console.log(err) 16 | } 17 | }); 18 | it('Factory deploy and checking the owner', async () => { 19 | try { 20 | let from = accounts[1]; 21 | let factory = await MultiSendWalletFactory.new() 22 | let deployed = await factory.deployNewWallet(from) 23 | let wallet = await MultiSendWallet.at(deployed.logs[0].args.wallet) 24 | let owner = await wallet.owner() 25 | assert.equal(owner, from); 26 | } catch (err) { 27 | console.log(err) 28 | } 29 | }); 30 | it('multi transfer (multiTransferERC20TightlyPacked)', async () => { 31 | try { 32 | let token = await Token.new() 33 | // Defaut token decimals == 18 34 | let mintValue = web3.utils.toWei(new BN('1000000000'), 'ether') 35 | let from = accounts[0]; 36 | let to = accounts[1]; 37 | let to2 = accounts[2] 38 | let amount = web3.utils.toWei(new BN('500000000'), 'ether') 39 | 40 | let balanceFrom = await token.balanceOf(from); 41 | 42 | assert.equal(balanceFrom.toString(), mintValue.toString()); 43 | 44 | let factory = await MultiSendWalletFactory.new() 45 | let deployed = await factory.deployNewWallet(from) 46 | let wallet = await MultiSendWallet.at(deployed.logs[0].args.wallet) 47 | let balanceTo = await token.balanceOf(to); 48 | let balanceTo2 = await token.balanceOf(to2); 49 | 50 | 51 | // Sending toknes to deployed contract wallet. 52 | await token.transfer(wallet.address, amount) 53 | 54 | let sendAmount = amount.div(new BN('2')) 55 | 56 | let send1 = "0x" + web3.utils.padLeft(sendAmount.toString('hex') + to.slice(2), 64) 57 | let send2 = "0x" + web3.utils.padLeft(sendAmount.toString('hex') + to2.slice(2), 64) 58 | // 0x00000001158e460913d00000943Bef1Fb2F25C43Ab4a010ae835E936d1A34fE1 59 | 60 | const txs = [ 61 | send1, send2 62 | ] 63 | 64 | // Should be 32bytes hex if calling from golang 65 | const inputDecimals = 18 66 | 67 | let logs = await wallet.multiTransferERC20TightlyPacked(token.address, txs, inputDecimals, { 68 | from: from 69 | }); 70 | 71 | //console.log(logs) 72 | 73 | let updateBalanceWallet = await token.balanceOf(wallet.address); 74 | let updateBalanceTo = await token.balanceOf(to); 75 | let updateBalanceTo2 = await token.balanceOf(to2); 76 | 77 | // Wallet balance should be zero 78 | assert.equal(new BN('0').toString(), updateBalanceWallet.toString()); 79 | assert.equal(balanceTo.add(sendAmount).toString(), updateBalanceTo.toString()); 80 | assert.equal(balanceTo2.add(sendAmount).toString(), updateBalanceTo2.toString()); 81 | } catch (err) { 82 | console.log(err) 83 | } 84 | }); 85 | 86 | }) -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Use this file to configure your truffle project. It's seeded with some 3 | * common settings for different networks and features like migrations, 4 | * compilation and testing. Uncomment the ones you need or modify 5 | * them to suit your project as necessary. 6 | * 7 | * More information about configuration can be found at: 8 | * 9 | * truffleframework.com/docs/advanced/configuration 10 | * 11 | * To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider) 12 | * to sign your transactions before they're sent to a remote public node. Infura accounts 13 | * are available for free at: infura.io/register. 14 | * 15 | * You'll also need a mnemonic - the twelve word phrase the wallet uses to generate 16 | * public/private key pairs. If you're publishing your code to GitHub make sure you load this 17 | * phrase from a file you've .gitignored so it doesn't accidentally become public. 18 | * 19 | */ 20 | 21 | // const HDWalletProvider = require('@truffle/hdwallet-provider'); 22 | // const infuraKey = "fj4jll3k....."; 23 | // 24 | // const fs = require('fs'); 25 | // const mnemonic = fs.readFileSync(".secret").toString().trim(); 26 | 27 | const HDWalletProvider = require('@truffle/hdwallet-provider'); 28 | 29 | const mnemonic = process.env.SEED 30 | 31 | 32 | module.exports = { 33 | /** 34 | * Networks define how you connect to your ethereum client and let you set the 35 | * defaults web3 uses to send transactions. If you don't specify one truffle 36 | * will spin up a development blockchain for you on port 9545 when you 37 | * run `develop` or `test`. You can ask a truffle command to use a specific 38 | * network from the command line, e.g 39 | * 40 | * $ truffle test --network 41 | */ 42 | 43 | networks: { 44 | // Useful for testing. The `development` name is special - truffle uses it by default 45 | // if it's defined here and no other network is specified at the command line. 46 | // You should run a client (like ganache-cli, geth or parity) in a separate terminal 47 | // tab if you use this network and you must also set the `host`, `port` and `network_id` 48 | // options below to some value. 49 | // 50 | development: { 51 | host: "127.0.0.1", // Localhost (default: none) 52 | port: 8545, // Standard Ethereum port (default: none) 53 | gasPrice: 70 * 10 ** 9, 54 | network_id: "*", // Any network (default: none) 55 | }, 56 | 57 | ropsten: { 58 | provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/540eda0de1434dacaee33f78f33aeb54`), 59 | network_id: 3, // BSC testnet id 60 | gas: 5500000, // BSC testnet has a lower block limit than mainnet 61 | confirmations: 3, // # of confs to wait between deployments. (default: 0) 62 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 63 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 64 | }, 65 | 66 | goerli: { 67 | provider: () => new HDWalletProvider(mnemonic, `https://goerli.infura.io/v3/540eda0de1434dacaee33f78f33aeb54`), 68 | network_id: 5, // BSC testnet id 69 | gas: 5500000, // BSC testnet has a lower block limit than mainnet 70 | confirmations: 3, // # of confs to wait between deployments. (default: 0) 71 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 72 | skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) 73 | }, 74 | // Another network with more advanced options... 75 | // advanced: { 76 | // port: 8777, // Custom port 77 | // network_id: 1342, // Custom network 78 | // gas: 8500000, // Gas sent with each transaction (default: ~6700000) 79 | // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) 80 | // from:
, // Account to send txs from (default: accounts[0]) 81 | // websockets: true // Enable EventEmitter interface for web3 (default: false) 82 | // }, 83 | // Useful for deploying to a public network. 84 | // NB: It's important to wrap the provider as a function. 85 | bsc_testnet: { 86 | provider: () => new HDWalletProvider(mnemonic, `https://data-seed-prebsc-1-s1.binance.org:8545`), 87 | network_id: 97, // Ropsten's id 88 | gas: 7500000, // Ropsten has a lower block limit than mainnet 89 | confirmations: 2, // # of confs to wait between deployments. (default: 0) 90 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 91 | skipDryRun: true, // Skip dry run before migrations? (default: false for public nets ) 92 | gasPrice: 10000000000 93 | }, 94 | bsc_mainnet: { 95 | provider: () => new HDWalletProvider(mnemonic, `https://bsc-dataseed.binance.org`, 0, 1, true, "m/44'/519'/0'/0/"), 96 | network_id: 56, // BSC testnet id 97 | gas: 1777648, // BSC testnet has a lower block limit than mainnet 98 | confirmations: 3, // # of confs to wait between deployments. (default: 0) 99 | timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) 100 | skipDryRun: true, // Skip dry run before migrations? (default: false for public nets ), 101 | gasPrice: 20 * 10 ** 9 102 | }, 103 | // Useful for private networks 104 | // private: { 105 | // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), 106 | // network_id: 2111, // This network is yours, in the cloud. 107 | // production: true // Treats this network as if it was a public net. (default: false) 108 | // } 109 | }, 110 | 111 | // Set default mocha options here, use special reporters etc. 112 | mocha: { 113 | // timeout: 100000 114 | }, 115 | 116 | // Configure your compilers 117 | compilers: { 118 | solc: { 119 | version: "0.5.16", // Fetch exact version from solc-bin (default: truffle's version) 120 | // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) 121 | // settings: { // See the solidity docs for advice about optimization and evmVersion 122 | // optimizer: { 123 | // enabled: false, 124 | // runs: 200 125 | // }, 126 | // evmVersion: "byzantium" 127 | // } 128 | }, 129 | }, 130 | }; 131 | --------------------------------------------------------------------------------