├── .eslintrc ├── .gitignore ├── .gitmodules ├── .solcover.js ├── .soliumignore ├── .soliumrc.json ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── SOLIDITY_STYLE_GUIDE.md ├── VERSION ├── contracts ├── BrandedToken.sol ├── EIP20Interface.sol ├── EIP20Token.sol ├── EIP20TokenMock.sol ├── GatewayComposer.sol ├── GatewayInterface.sol ├── UtilityBrandedToken.sol ├── test │ ├── MockCoGateway.sol │ ├── TestUtilityBrandedToken.sol │ ├── branded_token │ │ └── MockBrandedTokenFail.sol │ ├── eip20token │ │ ├── EIP20TokenMockFail.sol │ │ ├── EIP20TokenMockPass.sol │ │ └── EIP20TokenMockPassFail.sol │ ├── gateway │ │ ├── MockGatewayFail.sol │ │ └── MockGatewayPass.sol │ └── organization │ │ ├── OrganizationMockFail.sol │ │ ├── OrganizationMockPass.sol │ │ └── OrganizationMockWorker.sol └── truffle │ └── Migrations.sol ├── dist └── index.js ├── migrations └── 1_initial_migration.js ├── package-lock.json ├── package.json ├── test ├── branded_token │ ├── accept_stake_request.js │ ├── constructor.js │ ├── convert_to_branded_tokens.js │ ├── convert_to_value_tokens.js │ ├── lift_all_restrictions.js │ ├── lift_restriction.js │ ├── redeem.js │ ├── reject_stake_request.js │ ├── request_stake.js │ ├── revoke_stake_request.js │ ├── set_name.js │ ├── set_symbol.js │ ├── transfer.js │ ├── transferFrom.js │ └── utils.js ├── gateway_composer │ ├── accept_stake_request.js │ ├── approve_token.js │ ├── constructor.js │ ├── destroy.js │ ├── request_stake.js │ ├── revert_stake.js │ ├── revoke_stake_request.js │ ├── transfer_token.js │ └── utils.js ├── test_lib │ ├── RevertProxy.sol │ ├── config.js │ ├── event_decoder.js │ ├── utils.js │ └── web3.js └── utility_branded_token │ ├── constructor.js │ ├── decrease_supply.js │ ├── exists.js │ ├── increase_supply.js │ ├── register_internal_actors.js │ ├── set_cogateway.js │ ├── transfer.js │ ├── transfer_from.js │ └── utils.js ├── tools ├── build_package.js ├── compile.sh ├── runGanacheCli.sh └── test_range.sh └── truffle.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb-base" 4 | ], 5 | "rules": { 6 | "no-console": "off", 7 | "no-underscore-dangle": "off", 8 | "import/no-extraneous-dependencies": "off", 9 | "strict": "off" 10 | }, 11 | "env": { 12 | "mocha": true, 13 | "node": true, 14 | "es6": true 15 | }, 16 | "globals": { 17 | "artifacts": false, 18 | "contract": false, 19 | "assert": false 20 | } 21 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | .DS_Store 3 | .idea/ 4 | 5 | # VS Code 6 | .vscode 7 | 8 | # Vagrant 9 | .vagrant/ 10 | ubuntu-xenial-16.04-cloudimg-console.log 11 | 12 | # don't commit node_modules 13 | node_modules 14 | 15 | build/ 16 | 17 | contracts/abi/ 18 | contracts/bin/ 19 | 20 | # NPM package generated files: 21 | dist/contracts.json -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "contracts/utilitytoken"] 2 | path = contracts/utilitytoken 3 | url = https://github.com/OpenST/utilitytoken-contracts.git 4 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 8555, 3 | compileCommand: '../node_modules/.bin/truffle compile', 4 | testCommand: '../node_modules/.bin/truffle test --network coverage', 5 | skipFiles: ['truffle/Migrations.sol'] 6 | }; -------------------------------------------------------------------------------- /.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | contracts/Migrations.sol 3 | contracts/SafeMath.sol 4 | -------------------------------------------------------------------------------- /.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solium:recommended", 3 | "plugins": [ 4 | "security" 5 | ], 6 | "rules": { 7 | "imports-on-top": 0, 8 | "variable-declarations": 0, 9 | "quotes": [ 10 | "error", 11 | "double" 12 | ], 13 | "indentation": [ 14 | "error", 15 | 4 16 | ], 17 | "max-len": [ 18 | "error", 19 | 79 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: node_js 3 | sudo: required 4 | branches: 5 | only: 6 | - master 7 | - develop 8 | - /^release-.*/ 9 | notifications: 10 | email: 11 | recipients: 12 | - ci.report@ost.com 13 | on_success: always 14 | on_failure: always 15 | node_js: 16 | - "8" 17 | before_install: 18 | - sudo apt-get update 19 | - sudo apt-get install nodejs 20 | - sudo apt-get install npm 21 | install: 22 | - npm install 23 | before_script: 24 | - nohup sh tools/runGanacheCli.sh /dev/null 2>&1 & 25 | script: 26 | - npm run lint 27 | - npm run test 28 | - npm run compile-all 29 | - npm run build-package 30 | after_script: 31 | - kill $(ps aux | grep 'testrpc' | awk '{print $2}') 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Branded Token Contracts Change Log 2 | 3 | Below is a list of notable changes implemented in this repository. 4 | 5 | ## 0.10.0 6 | 7 | 8 | * Contracts: Implementation of exists in UtilityBrandedToken contract. ([#153](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/153)) 9 | * Contracts: Register cogateway as an internal actor on UtilityBrandedToken::setCoGateway(). ([#151](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/151)) 10 | * Contracts: Remove reentrancy from BrandedToken::acceptStakeRequest() ([#150](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/150)) 11 | * Contracts: GatewayComposer: Reentrancy evaluation and prevention mechanisms ([#147](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/147)) 12 | * Contracts: update and test SafeMath ([#127](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/127)) 13 | * Tests: Fix negative tests with unresolved promises ([#118](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/118)) 14 | * Tests: Complete testing of various BrandedToken functions ([#114](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/114)) 15 | * Tests: Add negative test for BrandedToken's liftAllRestrictions ([#111](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/111)) 16 | * Tests: Add negative test for BrandedToken's redeem ([#108](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/108)) 17 | * Contracts: Limit BrandedToken conversionRateDecimals to 5 ([#107](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/107)) 18 | * Contracts: Calculate stakeRequestHash per EIP 712 ([#105](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/105)) 19 | * Contracts: Add destroy to GatewayComposer ([#103](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/103)) 20 | * Contracts: Add setName and setSymbol for BrandedToken ([#102](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/102)) 21 | * Contracts: Initially implement GatewayComposer ([#88](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/88)) 22 | * Contracts: Add initial implementation of BrandedToken ([#87](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/87)) 23 | * Contracts: Update contracts for Solidity 0.5.0 ([#76](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/76)) 24 | * Tests: Test Internal ([#51](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/51)) 25 | * Contracts: Implement UtilityBrandedToken ([#47](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/47)) 26 | * Contracts: Add Internal for use with UtilityBrandedToken ([#43](https://github.com/OpenSTFoundation/brandedtoken-contracts/pull/43)) -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@ost.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Branded Tokens - Tokenizing Mainstream Applications

2 | 3 | [![Discourse: JOIN DISCUSSION](https://img.shields.io/discourse/https/discuss.openst.org/topics.svg?style=flat)](https://discuss.openst.org/) [![Travis CI: DEVELOP](https://img.shields.io/travis/OpenST/brandedtoken-contracts/develop.svg?style=flat)](https://travis-ci.org/OpenST/brandedtoken-contracts) 4 | 5 | A Branded Token allows a mainstream application to create a value-backed token designed specifically for its application's context. A Branded Token implements the required and optional [EIP-20 Standard Token interface](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md). 6 | 7 | Holders of branded tokens must be able to redeem the value that backs those branded tokens. Branded tokens are only usable within the application context. The application can maintain a policy on accepting new holders. 8 | 9 | A Utility Branded Token, which also implements the EIP-20 Standard Token interface, is the utility token representation of the Branded Token on a sidechain. This representation is orchestrated via a gateway, comprising a Gateway contract on the same chain as the Branded Token, and a CoGateway contract on the sidechain with the Utility Branded Token. 10 | 11 | A composer is a contract that can be used to optimize the transactions required to perform an action. A Gateway Composer, a type of composer, facilitate's staking value for branded tokens and minting a utility representation of those branded tokens with a Utility Branded Token through a gateway for use within the given application, thereby reducing both the number of transactions to execute and the number of contracts to call in order to stake and mint. 12 | 13 | The complete Branded Token specification is in a draft proposal and subject to change. For more information on the specification, please consult [OIP-0001](https://github.com/OpenST/OIPs/blob/master/OIPS/oip-0001.md) in the OpenST Improvement Proposals repository. 14 | 15 | ## Related Projects 16 | 17 | Significant related projects are: 18 | 19 | - [brandedtoken.js](https://github.com/OpenST/brandedtoken.js): a library for interacting with `BrandedToken` and `GatewayComposer` contracts. 20 | - [mosaic-contracts](https://github.com/OpenST/mosaic-contracts): a set of meta-blockchains on top of Ethereum to scale (D)Apps 21 | - [mosaic.js](https://github.com/OpenST/mosaic.js): a web3 interface to scale (D)Apps on Ethereum 22 | - [openst-contracts](https://github.com/OpenST/openst-contracts): a framework for building token economies 23 | - [openst.js](https://github.com/OpenST/openst.js): a library for deploying and interacting with a token economy 24 | 25 | ## Contributing 26 | 27 | There are multiple ways to contribute to this project. However, before contributing, please first review the [Code of Conduct](CODE_OF_CONDUCT.md). 28 | 29 | To participate in the discussion on technical matters, please join the project's [Discourse forum](https://discuss.openst.org/) channel or review the project's [issues](https://github.com/OpenSTFoundation/brandedtoken-contracts/issues). 30 | 31 | To contribute code, please ensure that your submissions adhere to the [Style Guide](SOLIDITY_STYLE_GUIDE.md); please also be aware, this project is under active development and we have not yet established firm contribution guidelines or acceptance criteria. 32 | 33 | ## OpenST 34 | 35 | OpenST blockchain infrastructure empowers new economies for mainstream businesses and emerging (D)Apps. The smart contracts in this repository are intended for use with the OpenST Protocol, a framework for tokenizing businesses. 36 | 37 | For more information on the OpenST Protocol, please consult the [Whitepaper](https://drive.google.com/file/d/0Bwgf8QuAEOb7Z2xIeUlLd21DSjQ/view). 38 | 39 | _While this software is available as-is for anyone to use, we caution that this is in early stage and under heavy ongoing development and improvement. Please report bugs and suggested improvements._ -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.10.0 -------------------------------------------------------------------------------- /contracts/EIP20Interface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | // ---------------------------------------------------------------------------- 18 | // Common: Standard EIP20 Interface 19 | // 20 | // http://www.simpletoken.org/ 21 | // 22 | // ---------------------------------------------------------------------------- 23 | // ---------------------------------------------------------------------------- 24 | // Based on the 'final' EIP20 token standard as specified at: 25 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 26 | // ---------------------------------------------------------------------------- 27 | 28 | /** 29 | * @title EIP20Interface. 30 | * 31 | * @notice Provides EIP20 token interface. 32 | */ 33 | contract EIP20Interface { 34 | 35 | /* Events */ 36 | 37 | event Transfer( 38 | address indexed _from, 39 | address indexed _to, 40 | uint256 _value 41 | ); 42 | 43 | event Approval( 44 | address indexed _owner, 45 | address indexed _spender, 46 | uint256 _value 47 | ); 48 | 49 | 50 | /* Public functions */ 51 | 52 | /** 53 | * @notice Public function to get the name of the token. 54 | * 55 | * @return tokenName_ Name of the token. 56 | */ 57 | function name() public view returns (string memory tokenName_); 58 | 59 | /** 60 | * @notice Public function to get the symbol of the token. 61 | * 62 | * @return tokenSymbol_ Symbol of the token. 63 | */ 64 | function symbol() public view returns (string memory tokenSymbol_); 65 | 66 | /** 67 | * @notice Public function to get the decimals of the token. 68 | * 69 | * @return tokenDecimals Decimals of the token. 70 | */ 71 | function decimals() public view returns (uint8 tokenDecimals_); 72 | 73 | /** 74 | * @notice Public function to get the total supply of the tokens. 75 | * 76 | * @return totalTokenSupply_ Total token supply. 77 | */ 78 | function totalSupply() 79 | public 80 | view 81 | returns (uint256 totalTokenSupply_); 82 | 83 | /** 84 | * @notice Get the balance of an account. 85 | * 86 | * @param _owner Address of the owner account. 87 | * 88 | * @return balance_ Account balance of the owner account. 89 | */ 90 | function balanceOf(address _owner) public view returns (uint256 balance_); 91 | 92 | /** 93 | * @notice Public function to get the allowance. 94 | * 95 | * @param _owner Address of the owner account. 96 | * @param _spender Address of the spender account. 97 | * 98 | * @return allowance_ Remaining allowance for the spender to spend from 99 | * owner's account. 100 | */ 101 | function allowance( 102 | address _owner, 103 | address _spender 104 | ) 105 | public 106 | view 107 | returns (uint256 allowance_); 108 | 109 | 110 | /** 111 | * @notice Public function to transfer the token. 112 | * 113 | * @param _to Address to which tokens are transferred. 114 | * @param _value Amount of tokens to be transferred. 115 | * 116 | * @return success_ `true` for a successful transfer, `false` otherwise. 117 | */ 118 | function transfer( 119 | address _to, 120 | uint256 _value 121 | ) 122 | public 123 | returns (bool success_); 124 | 125 | /** 126 | * @notice Public function transferFrom. 127 | * 128 | * @param _from Address from which tokens are transferred. 129 | * @param _to Address to which tokens are transferred. 130 | * @param _value Amount of tokens transferred. 131 | * 132 | * @return success_ `true` for a successful transfer, `false` otherwise. 133 | */ 134 | function transferFrom( 135 | address _from, 136 | address _to, 137 | uint256 _value 138 | ) 139 | public 140 | returns (bool success_); 141 | 142 | /** 143 | * @notice Public function to approve an account for transfer. 144 | * 145 | * @param _spender Address authorized to spend from the function caller's 146 | * address. 147 | * @param _value Amount up to which spender is authorized to spend. 148 | * 149 | * @return bool `true` for a successful approval, `false` otherwise. 150 | */ 151 | function approve( 152 | address _spender, 153 | uint256 _value 154 | ) 155 | public 156 | returns (bool success_); 157 | 158 | } 159 | -------------------------------------------------------------------------------- /contracts/EIP20Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import "./EIP20Interface.sol"; 18 | import "openzeppelin-solidity/contracts/math/SafeMath.sol"; 19 | 20 | 21 | /** 22 | * @title EIP20Token contract which implements EIP20Interface. 23 | * 24 | * @notice Implements EIP20 token. 25 | */ 26 | contract EIP20Token is EIP20Interface { 27 | 28 | using SafeMath for uint256; 29 | 30 | 31 | /* Storage */ 32 | 33 | string internal tokenName; 34 | string internal tokenSymbol; 35 | uint8 private tokenDecimals; 36 | uint256 internal totalTokenSupply; 37 | 38 | mapping(address => uint256) balances; 39 | mapping(address => mapping (address => uint256)) allowed; 40 | 41 | 42 | /* Special functions */ 43 | 44 | /** 45 | * @notice Contract constructor. 46 | * 47 | * @param _symbol Symbol of the token. 48 | * @param _name Name of the token. 49 | * @param _decimals Decimal places of the token. 50 | */ 51 | constructor( 52 | string memory _symbol, 53 | string memory _name, 54 | uint8 _decimals 55 | ) 56 | public 57 | { 58 | tokenSymbol = _symbol; 59 | tokenName = _name; 60 | tokenDecimals = _decimals; 61 | totalTokenSupply = 0; 62 | } 63 | 64 | 65 | /* Public functions */ 66 | 67 | /** 68 | * @notice Public view function name. 69 | * 70 | * @return Name of the token. 71 | */ 72 | function name() public view returns (string memory) { 73 | return tokenName; 74 | } 75 | 76 | /** 77 | * @notice Public view function symbol. 78 | * 79 | * @return Symbol of the token. 80 | */ 81 | function symbol() public view returns (string memory) { 82 | return tokenSymbol; 83 | } 84 | 85 | /** 86 | * @notice Public view function decimals. 87 | * 88 | * @return Decimal places of the token. 89 | */ 90 | function decimals() public view returns (uint8) { 91 | return tokenDecimals; 92 | } 93 | 94 | /** 95 | * @notice Public view function balanceOf. 96 | * 97 | * @param _owner Address of the owner account. 98 | * 99 | * @return Account balance of the owner account. 100 | */ 101 | function balanceOf(address _owner) public view returns (uint256) { 102 | return balances[_owner]; 103 | } 104 | 105 | /** 106 | * @notice Public view function totalSupply. 107 | * 108 | * @dev Get totalTokenSupply as view so that child cannot edit. 109 | * 110 | * @return Total token supply. 111 | */ 112 | function totalSupply() 113 | public 114 | view 115 | returns (uint256) 116 | { 117 | return totalTokenSupply; 118 | } 119 | 120 | /** 121 | * @notice Public view function allowance. 122 | * 123 | * @param _owner Address of the owner account. 124 | * @param _spender Address of the spender account. 125 | * 126 | * @return Remaining allowance for the spender to spend from 127 | * owner's account. 128 | */ 129 | function allowance( 130 | address _owner, 131 | address _spender 132 | ) 133 | public 134 | view 135 | returns (uint256) 136 | { 137 | return allowed[_owner][_spender]; 138 | } 139 | 140 | /** 141 | * @notice Public function transfer. 142 | * 143 | * @dev Fires the transfer event, throws if, _from account does not have 144 | * enough tokens to spend. 145 | * 146 | * @param _to Address to which tokens are transferred. 147 | * @param _value Amount of tokens to be transferred. 148 | * 149 | * @return success_ True for a successful transfer, false otherwise. 150 | */ 151 | function transfer( 152 | address _to, 153 | uint256 _value 154 | ) 155 | public 156 | returns (bool success_) 157 | { 158 | 159 | // According to the EIP20 spec, "transfers of 0 values MUST be treated 160 | // as normal transfers and fire the Transfer event". 161 | // Also, should throw if not enough balance. This is taken care of by 162 | // SafeMath. 163 | balances[msg.sender] = balances[msg.sender].sub(_value); 164 | balances[_to] = balances[_to].add(_value); 165 | 166 | emit Transfer(msg.sender, _to, _value); 167 | 168 | return true; 169 | } 170 | 171 | /** 172 | * @notice Public function transferFrom. 173 | * 174 | * @dev Allows a contract to transfer tokens on behalf of _from address 175 | * to _to address, the function caller has to be pre-authorized 176 | * for multiple transfers up to the total of _value amount by 177 | * the _from address. 178 | * 179 | * @param _from Address from which tokens are transferred. 180 | * @param _to Address to which tokens are transferred. 181 | * @param _value Amount of tokens transferred. 182 | * 183 | * @return success_ True for a successful transfer, false otherwise. 184 | */ 185 | function transferFrom( 186 | address _from, 187 | address _to, 188 | uint256 _value 189 | ) 190 | public 191 | returns (bool success_) 192 | { 193 | balances[_from] = balances[_from].sub(_value); 194 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 195 | balances[_to] = balances[_to].add(_value); 196 | 197 | emit Transfer(_from, _to, _value); 198 | 199 | return true; 200 | } 201 | 202 | /** 203 | * @notice Public function approve. 204 | * 205 | * @dev Allows _spender address to withdraw from function caller's 206 | * account, multiple times up to the _value amount, if this 207 | * function is called again it overwrites the current allowance 208 | * with _value. 209 | * 210 | * @param _spender Address authorized to spend from the function caller's 211 | * address. 212 | * @param _value Amount up to which spender is authorized to spend. 213 | * 214 | * @return success_ True for a successful approval, false otherwise. 215 | */ 216 | function approve( 217 | address _spender, 218 | uint256 _value 219 | ) 220 | public 221 | returns (bool success_) 222 | { 223 | 224 | allowed[msg.sender][_spender] = _value; 225 | 226 | emit Approval(msg.sender, _spender, _value); 227 | 228 | return true; 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /contracts/EIP20TokenMock.sol: -------------------------------------------------------------------------------- 1 | /* solhint-disable-next-line compiler-fixed */ 2 | pragma solidity ^0.5.0; 3 | 4 | // Copyright 2018 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | import "./EIP20Token.sol"; 19 | 20 | 21 | /** 22 | * @title EIP20TokenMock contract. 23 | * 24 | * @notice It provides EIP20Token with mock functionality to facilitate 25 | * testing. 26 | */ 27 | contract EIP20TokenMock is EIP20Token { 28 | 29 | /* Special functions */ 30 | 31 | /** 32 | * @dev Takes _symbol, _name, _decimals. 33 | * 34 | * @param _symbol Symbol. 35 | * @param _name Name. 36 | * @param _decimals Decimals. 37 | */ 38 | constructor( 39 | string memory _symbol, 40 | string memory _name, 41 | uint8 _decimals 42 | ) 43 | /* solhint-disable-next-line visibility-modifier-order */ 44 | EIP20Token(_symbol, _name, _decimals) 45 | public 46 | { } 47 | 48 | 49 | /* Public functions */ 50 | 51 | /** 52 | * @notice Returns 0 as mock total supply. 53 | * 54 | * @return Returns 0. 55 | */ 56 | function totalSupply() 57 | public 58 | view 59 | returns (uint256) 60 | { 61 | return 0; 62 | } 63 | 64 | /** 65 | * @notice Takes _owner, _value; sets balance of _owner to _value. 66 | * 67 | * @param _owner Owner. 68 | * @param _value Value. 69 | * 70 | * @return True if balances of the _owner is set. 71 | */ 72 | function setBalance( 73 | address _owner, 74 | uint256 _value 75 | ) 76 | public 77 | returns (bool) 78 | { 79 | balances[_owner] = _value; 80 | return true; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /contracts/GatewayInterface.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | 18 | /** 19 | * @title GatewayInterface Contract 20 | * 21 | * @notice Provides interface for gateway contract. 22 | */ 23 | interface GatewayInterface { 24 | 25 | /* External functions */ 26 | 27 | /** 28 | * @notice Returns bounty amount. 29 | * 30 | * @return Amount of ERC20 which needs to be staked by facilitator. 31 | */ 32 | function bounty() 33 | external 34 | returns (uint256); 35 | 36 | /** 37 | * @notice Initiates the stake process. In order to stake the staker 38 | * needs to approve Gateway contract for stake amount. 39 | * Staked amount is transferred from staker address to 40 | * Gateway contract. Bounty amount is also transferred from staker. 41 | * 42 | * @param _amount Stake amount that will be transferred from the staker 43 | * account. 44 | * @param _beneficiary The address in the auxiliary chain where the utility 45 | * tokens will be minted. 46 | * @param _gasPrice Gas price that staker is ready to pay to get the stake 47 | * and mint process done. 48 | * @param _gasLimit Gas limit that staker is ready to pay. 49 | * @param _nonce Nonce of the staker address. 50 | * @param _hashLock Hash Lock provided by the facilitator. 51 | * 52 | * @return messageHash_ Message hash is unique for each request. 53 | */ 54 | function stake( 55 | uint256 _amount, 56 | address _beneficiary, 57 | uint256 _gasPrice, 58 | uint256 _gasLimit, 59 | uint256 _nonce, 60 | bytes32 _hashLock 61 | ) 62 | external 63 | returns (bytes32 messageHash_); 64 | 65 | /** 66 | * @notice Revert stake process and get the stake 67 | * amount back. Only staker can revert stake by providing 68 | * penalty i.e. 1.5 times of bounty amount. On progress revert stake 69 | * penalty and facilitator bounty will be burned. 70 | * 71 | * @dev To revert the the sender must sign the sha3(messageHash, nonce+1) 72 | * 73 | * @param _messageHash Message hash. 74 | * 75 | * @return staker_ Staker address 76 | * @return stakerNonce_ Staker nonce 77 | * @return amount_ Stake amount 78 | */ 79 | function revertStake( 80 | bytes32 _messageHash 81 | ) 82 | external 83 | returns 84 | ( 85 | address staker_, 86 | uint256 stakerNonce_, 87 | uint256 amount_ 88 | ); 89 | } 90 | -------------------------------------------------------------------------------- /contracts/UtilityBrandedToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import "./utilitytoken/contracts/UtilityToken.sol"; 18 | 19 | 20 | /** 21 | * @title UtilityBrandedToken contract. 22 | * 23 | * @notice UtilityBrandedToken is an EIP20 token which implements 24 | * UtilityTokenInterface. 25 | * 26 | * @dev UtilityBrandedToken are designed to be used within a decentralised 27 | * application and support increaseSupply and decreaseSupply of tokens. 28 | */ 29 | contract UtilityBrandedToken is UtilityToken { 30 | 31 | /* Events */ 32 | 33 | event InternalActorRegistered( 34 | address _actor 35 | ); 36 | 37 | 38 | /* Storage */ 39 | 40 | /** Mapping stores addresses which are registered as internal actor. */ 41 | mapping (address /* internal actor */ => bool) public isInternalActor; 42 | 43 | 44 | /* Special Functions */ 45 | 46 | /** 47 | * @notice Contract constructor. 48 | * 49 | * @dev Creates an utility branded token contract with arguments passed 50 | * in the contract constructor. 51 | * 52 | * @param _token Address of branded token on origin chain. 53 | * It acts as an identifier. 54 | * @param _symbol Symbol of the token. 55 | * @param _name Name of the token. 56 | * @param _decimals Decimal places of the token. 57 | * @param _organization Address of the Organization contract. 58 | */ 59 | constructor( 60 | address _token, 61 | string memory _symbol, 62 | string memory _name, 63 | uint8 _decimals, 64 | OrganizationInterface _organization 65 | ) 66 | public 67 | UtilityToken(_token, _symbol, _name, _decimals, _organization) 68 | { 69 | } 70 | 71 | 72 | /* External functions */ 73 | 74 | /** 75 | * @notice Registers internal actors. 76 | * 77 | * @param _internalActors Array of addresses of the internal actors 78 | * to register. 79 | */ 80 | function registerInternalActors(address[] calldata _internalActors) 81 | external 82 | onlyWorker 83 | { 84 | for (uint256 i = 0; i < _internalActors.length; i++) { 85 | if (!isInternalActor[_internalActors[i]]) { 86 | isInternalActor[_internalActors[i]] = true; 87 | emit InternalActorRegistered(_internalActors[i]); 88 | } 89 | } 90 | } 91 | 92 | /** 93 | * @notice Sets the CoGateway contract address. 94 | * 95 | * @dev Function requires: 96 | * - Caller is organization. 97 | * - coGateway address is not set. 98 | * - coGateway.utilityToken is equal to this contract address. 99 | * 100 | * @param _coGateway CoGateway contract address. 101 | */ 102 | function setCoGateway(address _coGateway) 103 | external 104 | onlyOrganization 105 | returns (bool success_) 106 | { 107 | success_ = super.setCoGatewayInternal(_coGateway); 108 | 109 | // Registers co-gateway as an internal actor. 110 | isInternalActor[coGateway] = true; 111 | } 112 | 113 | /** 114 | * @notice Increases the total token supply. Also, adds the number of 115 | * tokens to the beneficiary balance. 116 | * 117 | * @param _beneficiary Account address for which the balance will be 118 | * increased. This is payable so that it provides 119 | * flexibility of transferring base token to account 120 | * on increase supply. 121 | * @param _amount Amount of tokens. 122 | * 123 | * @return success_ `true` if increase supply is successful, false otherwise. 124 | */ 125 | function increaseSupply( 126 | address payable _beneficiary, 127 | uint256 _amount 128 | ) 129 | external 130 | onlyCoGateway 131 | returns (bool success_) 132 | { 133 | require( 134 | isInternalActor[_beneficiary], 135 | "Beneficiary is not an internal actor." 136 | ); 137 | 138 | success_ = super.increaseSupplyInternal(_beneficiary, _amount); 139 | } 140 | 141 | /** 142 | * @notice Checks if an address is an internal actor. 143 | * 144 | * @return exists_ `true` if the specified account is an internal actor, 145 | * otherwise `false`. 146 | */ 147 | function exists(address account) external returns (bool exists_) { 148 | exists_ = isInternalActor[account]; 149 | } 150 | 151 | 152 | /* Public functions */ 153 | 154 | /** 155 | * @notice Public function transfer. 156 | * 157 | * @dev Function requires: 158 | * - _to address is an internal actor 159 | * 160 | * @param _to Address to which BT needs to transfer. 161 | * @param _value Number of BTs that needs to transfer. 162 | * 163 | * @return Success/failure status of transfer. 164 | */ 165 | function transfer( 166 | address _to, 167 | uint256 _value 168 | ) 169 | public 170 | returns (bool) 171 | { 172 | require( 173 | isInternalActor[_to], 174 | "To address is not an internal actor." 175 | ); 176 | 177 | return super.transfer(_to, _value); 178 | } 179 | 180 | /** 181 | * @notice Public function transferFrom. 182 | * 183 | * @dev Function requires: 184 | * - _to address is an internal actor 185 | * 186 | * @param _from Address from which BT needs to transfer. 187 | * @param _to Address to which BT needs to transfer. 188 | * @param _value Number of BTs that needs to transfer. 189 | * 190 | * @return Success/failure status of transferFrom. 191 | */ 192 | function transferFrom( 193 | address _from, 194 | address _to, 195 | uint256 _value 196 | ) 197 | public 198 | returns (bool) 199 | { 200 | require( 201 | isInternalActor[_to], 202 | "To address is not an internal actor." 203 | ); 204 | 205 | return super.transferFrom(_from, _to, _value); 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /contracts/test/MockCoGateway.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | 18 | /** 19 | * @title MockCoGateway contract. 20 | * 21 | * @notice It contains utility token address. 22 | */ 23 | contract MockCoGateway { 24 | 25 | 26 | /* Storage */ 27 | 28 | /** Address of utilityToken */ 29 | address private token; 30 | 31 | 32 | /* Special functions */ 33 | 34 | constructor(address _token) public { 35 | 36 | token = _token; 37 | 38 | } 39 | 40 | 41 | /* Public methods */ 42 | 43 | /** 44 | * @notice Get the utility token address. 45 | * 46 | * @return Address of utility token. 47 | */ 48 | function utilityToken() public view returns (address) 49 | { 50 | return token; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /contracts/test/TestUtilityBrandedToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import "../UtilityBrandedToken.sol"; 18 | import "../utilitytoken/contracts/organization/contracts/OrganizationInterface.sol"; 19 | 20 | 21 | /** 22 | * @title TestUtilityBrandedToken contract. 23 | * 24 | * @notice UtilityBrandedToken is inheriting UtilityBrandedToken contract. 25 | * 26 | * @dev TestUtilityBrandedToken facilitates testing of UtilityBrandedToken. 27 | * 28 | */ 29 | contract TestUtilityBrandedToken is UtilityBrandedToken { 30 | 31 | /* Special Function */ 32 | 33 | /** 34 | * @notice Contract constructor. 35 | * 36 | * @dev Creates an EIP20Token contract with arguments passed in the 37 | * contract constructor. 38 | * 39 | * @param _token Address of branded token on origin chain. 40 | * It acts as an identifier. 41 | * @param _symbol Symbol of the token. 42 | * @param _name Name of the token. 43 | * @param _decimals Decimal places of the token. 44 | * @param _organization Address of the Organization contract. 45 | */ 46 | constructor( 47 | address _token, 48 | string memory _symbol, 49 | string memory _name, 50 | uint8 _decimals, 51 | OrganizationInterface _organization 52 | ) 53 | public 54 | UtilityBrandedToken(_token, _symbol, _name, _decimals, _organization) 55 | {} 56 | 57 | 58 | /* Public functions */ 59 | 60 | /** 61 | * @dev Takes _owner, _value; sets balance of _owner to _value. 62 | * 63 | * @notice It sets the balance for an address. 64 | * 65 | * @param _owner Owner address. 66 | * @param _value Amount of BT's to be set. 67 | * 68 | * @return True if success. 69 | */ 70 | function setBalance( 71 | address _owner, 72 | uint256 _value 73 | ) 74 | public 75 | returns (bool) 76 | { 77 | balances[_owner] = _value; 78 | return true; 79 | } 80 | 81 | /** 82 | * @dev It is used in testing increaseSupply and decreaseSupply methods. 83 | * 84 | * @notice It sets the coGateway address. 85 | * 86 | * @param _coGatewayAddress CoGateway contract address. 87 | */ 88 | function mockSetCoGateway(address _coGatewayAddress) public { 89 | coGateway = _coGatewayAddress; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /contracts/test/branded_token/MockBrandedTokenFail.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import "./../../BrandedToken.sol"; 18 | 19 | 20 | /** 21 | * @title MockBrandedTokenFail. 22 | * 23 | * @notice Supports testing of BrandedToken(BT) failure cases. 24 | */ 25 | contract MockBrandedTokenFail is BrandedToken { 26 | 27 | /* Special Functions */ 28 | 29 | /** 30 | * @dev Conversion parameters provide the conversion rate and its scale. 31 | * For example, if 1 value token is equivalent to 3.5 branded 32 | * tokens (1:3.5), _conversionRate == 35 and _conversionRateDecimals == 1. 33 | * 34 | * @param _valueToken The value to which valueToken is set. 35 | * @param _symbol The value to which tokenSymbol, defined in EIP20Token, is set. 36 | * @param _name The value to which tokenName, defined in EIP20Token, is set. 37 | * @param _decimals The value to which tokenDecimals, defined in EIP20Token, is set. 38 | * @param _conversionRate The value to which conversionRate is set. 39 | * @param _conversionRateDecimals The value to which conversionRateDecimals 40 | * is set. 41 | * @param _organization The value to which organization, defined in Organized, is set. 42 | */ 43 | constructor( 44 | EIP20Interface _valueToken, 45 | string memory _symbol, 46 | string memory _name, 47 | uint8 _decimals, 48 | uint256 _conversionRate, 49 | uint8 _conversionRateDecimals, 50 | OrganizationInterface _organization 51 | ) 52 | BrandedToken( 53 | _valueToken, 54 | _symbol, 55 | _name, 56 | _decimals, 57 | _conversionRate, 58 | _conversionRateDecimals, 59 | _organization 60 | ) 61 | public 62 | {} 63 | 64 | 65 | /* External Functions */ 66 | 67 | /** 68 | * @notice Mocks BrandedToken requestStake function. 69 | * 70 | * @dev It takes below parameters in order: 71 | * - amount to stake 72 | * - amount to mint 73 | * 74 | * @return Unique hash for each stake request. 75 | */ 76 | function requestStake( 77 | uint256, 78 | uint256 79 | ) 80 | external 81 | returns (bytes32) 82 | { 83 | 84 | return bytes32(0); 85 | } 86 | 87 | /** 88 | * @notice Mocks BrandedToken acceptStakeRequest function. It fails the execution. 89 | * 90 | * @dev It takes below parameters in order: 91 | * - stake request hash 92 | * - r is the actual signature 93 | * - s is the second point on the curve in order to ecrecover 94 | * - v selects the final public key 95 | */ 96 | function acceptStakeRequest( 97 | bytes32, 98 | bytes32, 99 | bytes32, 100 | uint8 101 | ) 102 | external 103 | returns (bool) 104 | { 105 | require(false, "BrandedToken acceptStakeRequest returned false."); 106 | } 107 | 108 | /** 109 | * @notice Mocks BrandedToken.revokeStakeRequest() function. 110 | * 111 | * @dev It takes below parameters in order: 112 | * - stake request hash 113 | * 114 | * @return False to replicate failure cases. 115 | */ 116 | function revokeStakeRequest( 117 | bytes32 118 | ) 119 | external 120 | returns (bool) 121 | { 122 | return false; 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /contracts/test/eip20token/EIP20TokenMockFail.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | // Copyright 2019 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | 20 | 21 | import "../../EIP20TokenMock.sol"; 22 | 23 | 24 | /** 25 | * @title Mock EIP20 Token Fail. 26 | * 27 | * @notice Mocks EIP20 token functions as failing. 28 | */ 29 | contract EIP20TokenMockFail is EIP20TokenMock { 30 | 31 | /* Constructor */ 32 | 33 | /** 34 | * @param _symbol The value to which tokenSymbol, defined in EIP20Token, 35 | * is set. 36 | * @param _name The value to which tokenName, defined in EIP20Token, 37 | * is set. 38 | * @param _decimals The value to which tokenDecimals, defined in EIP20Token, 39 | * is set. 40 | */ 41 | constructor( 42 | string memory _symbol, 43 | string memory _name, 44 | uint8 _decimals 45 | ) 46 | EIP20TokenMock(_symbol, _name, _decimals) 47 | public 48 | { } 49 | 50 | 51 | /* External Functions */ 52 | 53 | /** 54 | * @notice Mocks failing transferFrom. 55 | * 56 | * @return bool False. 57 | */ 58 | function transferFrom( 59 | address, 60 | address, 61 | uint256 62 | ) 63 | public 64 | returns (bool) 65 | { 66 | return false; 67 | } 68 | } -------------------------------------------------------------------------------- /contracts/test/eip20token/EIP20TokenMockPass.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | // Copyright 2019 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | import "../../EIP20TokenMock.sol"; 20 | 21 | 22 | /** 23 | * @title Mock EIP20 Token Pass. 24 | * 25 | * @notice Mocks EIP20 token functions as passing. 26 | */ 27 | contract EIP20TokenMockPass is EIP20TokenMock { 28 | 29 | /* Constructor */ 30 | 31 | /** 32 | * @param _symbol The value to which tokenSymbol, defined in EIP20Token, 33 | * is set. 34 | * @param _name The value to which tokenName, defined in EIP20Token, 35 | * is set. 36 | * @param _decimals The value to which tokenDecimals, defined in EIP20Token, 37 | * is set. 38 | */ 39 | constructor( 40 | string memory _symbol, 41 | string memory _name, 42 | uint8 _decimals 43 | ) 44 | EIP20TokenMock(_symbol, _name, _decimals) 45 | public 46 | { } 47 | 48 | 49 | /* External Functions */ 50 | 51 | /** 52 | * @notice Mocks passing transferFrom. 53 | * 54 | * @return bool True. 55 | */ 56 | function transferFrom( 57 | address, 58 | address, 59 | uint256 60 | ) 61 | public 62 | returns (bool) 63 | { 64 | return true; 65 | } 66 | 67 | /** 68 | * @notice Mocks passing transfer. 69 | * 70 | * @return bool True. 71 | */ 72 | function transfer( 73 | address, 74 | uint256 75 | ) 76 | public 77 | returns (bool) 78 | { 79 | return true; 80 | } 81 | } -------------------------------------------------------------------------------- /contracts/test/eip20token/EIP20TokenMockPassFail.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | // Copyright 2019 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | import "../../EIP20TokenMock.sol"; 20 | 21 | 22 | /** 23 | * @title Mock EIP20 Token Pass Fail. 24 | * 25 | * @notice Mocks EIP20 token transferFrom as passing and transfer as failing. 26 | * Passing transferFrom but failing transfer enables testing 27 | * functions that invoke transfer but can only be successfully 28 | * called after successfully invoking transferFrom. 29 | */ 30 | contract EIP20TokenMockPassFail is EIP20TokenMock { 31 | 32 | /* Constructor */ 33 | 34 | /** 35 | * @param _symbol The value to which tokenSymbol, defined in EIP20Token, 36 | * is set. 37 | * @param _name The value to which tokenName, defined in EIP20Token, 38 | * is set. 39 | * @param _decimals The value to which tokenDecimals, defined in EIP20Token, 40 | * is set. 41 | */ 42 | constructor( 43 | string memory _symbol, 44 | string memory _name, 45 | uint8 _decimals 46 | ) 47 | EIP20TokenMock(_symbol, _name, _decimals) 48 | public 49 | { } 50 | 51 | 52 | /* External Functions */ 53 | 54 | /** 55 | * @notice Mocks passing transferFrom. 56 | * 57 | * @dev Passing transferFrom enable 58 | * the signature of a worker, as defined in Organization. 59 | * 60 | * @return bool True. 61 | */ 62 | function transferFrom( 63 | address, 64 | address, 65 | uint256 66 | ) 67 | public 68 | returns (bool) 69 | { 70 | return true; 71 | } 72 | 73 | /** 74 | * @notice Mocks failing transfer. 75 | * 76 | * @return bool False. 77 | */ 78 | function transfer( 79 | address, 80 | uint256 81 | ) 82 | public 83 | returns (bool) 84 | { 85 | return false; 86 | } 87 | } -------------------------------------------------------------------------------- /contracts/test/gateway/MockGatewayFail.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | 18 | /** 19 | * @title MockGatewayFail contract. 20 | * 21 | * @notice Mocks gateway contract for negative test cases. 22 | */ 23 | contract MockGatewayFail { 24 | 25 | /* External Functions */ 26 | 27 | /** 28 | * @notice Returns bounty amount. 29 | * 30 | * @return Amount of ERC20 which needs to be staked by facilitator. 31 | */ 32 | function bounty() 33 | external 34 | pure 35 | returns (uint256) 36 | { 37 | return 10; 38 | } 39 | 40 | /** 41 | * @notice Mocks gateway.stake. It fails the execution. 42 | * 43 | * @dev parameters are in below order: 44 | * _amount 45 | * _beneficiary 46 | * _gasPrice 47 | * _gasLimit 48 | * _nonce 49 | * _hashLock 50 | * 51 | */ 52 | function stake( 53 | uint256, 54 | address, 55 | uint256, 56 | uint256, 57 | uint256, 58 | bytes32 59 | ) 60 | pure 61 | external 62 | returns (bytes32) 63 | { 64 | require(false, "Gateway.stake() execution failed."); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /contracts/test/gateway/MockGatewayPass.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | 18 | /** 19 | * @title MockGatewayPass contract. 20 | * 21 | * @notice Mocks gateway contract with successful returns. 22 | */ 23 | contract MockGatewayPass { 24 | 25 | /* External Functions */ 26 | 27 | /** 28 | * @notice Returns bounty amount. 29 | * 30 | * @return Amount of ERC20 which needs to be staked by facilitator. 31 | */ 32 | function bounty() 33 | external 34 | pure 35 | returns (uint256) 36 | { 37 | return 0; 38 | } 39 | 40 | /** 41 | * @notice Initiates the stake process. In order to stake the staker 42 | * needs to approve Gateway contract for stake amount. 43 | * Staked amount is transferred from staker address to 44 | * Gateway contract. Bounty amount is also transferred from staker. 45 | * 46 | * @dev parameters are in below order: 47 | * _amount 48 | * _beneficiary 49 | * _gasPrice 50 | * _gasLimit 51 | * _nonce 52 | * _hashLock 53 | * 54 | * @return Message hash unique for each request. 55 | */ 56 | function stake( 57 | uint256, 58 | address, 59 | uint256, 60 | uint256, 61 | uint256, 62 | bytes32 63 | ) 64 | external 65 | pure 66 | returns (bytes32) 67 | { 68 | return bytes32(0); 69 | } 70 | 71 | /** 72 | * @notice Revert stake process and get the stake 73 | * amount back. Only staker can revert stake by providing 74 | * penalty i.e. 1.5 times of bounty amount. On progress revert stake 75 | * penalty and facilitator bounty will be burned. 76 | * 77 | * @dev The only parameter is _messageHash. 78 | * 79 | * Returns are in below order: 80 | * - staker_ 81 | * - stakerNonce_ 82 | * - amount_ 83 | */ 84 | function revertStake( 85 | bytes32 86 | ) 87 | external 88 | pure 89 | returns (address, uint256, uint256) 90 | { 91 | return (address(0), uint256(0), uint256(0)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /contracts/test/organization/OrganizationMockFail.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | // Copyright 2019 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | /** 20 | * @title Mock Organization Fail. 21 | * 22 | * @notice Mocks Organization functions as failing. 23 | */ 24 | contract OrganizationMockFail { 25 | 26 | /* External Functions */ 27 | 28 | /** 29 | * @notice Mocks failing isOrganization. 30 | * 31 | * @return bool False. 32 | */ 33 | function isOrganization(address) 34 | external 35 | pure 36 | returns (bool) 37 | { 38 | return false; 39 | } 40 | 41 | /** 42 | * @notice Mocks failing isWorker. 43 | * 44 | * @return bool False. 45 | */ 46 | function isWorker(address) 47 | external 48 | pure 49 | returns (bool) 50 | { 51 | return false; 52 | } 53 | } -------------------------------------------------------------------------------- /contracts/test/organization/OrganizationMockPass.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | // Copyright 2019 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | /** 20 | * @title Organization Mock Pass. 21 | * 22 | * @notice Mocks Organization functions as passing. 23 | */ 24 | contract OrganizationMockPass { 25 | 26 | /* External Functions */ 27 | 28 | /** 29 | * @notice Mocks passing isOrganization. 30 | * 31 | * @return bool True. 32 | */ 33 | function isOrganization(address) 34 | external 35 | pure 36 | returns (bool) 37 | { 38 | return true; 39 | } 40 | 41 | /** 42 | * @notice Mocks passing isWorker. 43 | * 44 | * @return bool True. 45 | */ 46 | function isWorker(address) 47 | external 48 | pure 49 | returns (bool) 50 | { 51 | return true; 52 | } 53 | } -------------------------------------------------------------------------------- /contracts/test/organization/OrganizationMockWorker.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | 4 | // Copyright 2019 OpenST Ltd. 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | 19 | /** 20 | * @title Organization Mock Worker. 21 | * 22 | * @notice Mocks Organization setWorker and isWorker functions. 23 | */ 24 | contract OrganizationMockWorker { 25 | 26 | address public worker; 27 | 28 | /* External Functions */ 29 | 30 | /** 31 | * @notice Mocks setWorker. 32 | * 33 | * @param _worker The value to which worker is set. 34 | */ 35 | function setWorker( 36 | address _worker, 37 | uint256 38 | ) 39 | external 40 | { 41 | worker = _worker; 42 | } 43 | 44 | /** 45 | * @notice Mocks isWorker. 46 | * 47 | * @return bool True if worker == _worker, false if not. 48 | */ 49 | function isWorker( 50 | address _worker 51 | ) 52 | external 53 | view 54 | returns (bool) 55 | { 56 | return worker == _worker; 57 | } 58 | } -------------------------------------------------------------------------------- /contracts/truffle/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract Migrations { 4 | 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | modifier restricted() { 9 | if (msg.sender == owner) _; 10 | } 11 | 12 | constructor() public { 13 | owner = msg.sender; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | 20 | function upgrade(address new_address) public restricted { 21 | Migrations upgraded = Migrations(new_address); 22 | upgraded.setCompleted(last_completed_migration); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // ---------------------------------------------------------------------------- 16 | // 17 | // http://www.simpletoken.org/ 18 | // 19 | // ---------------------------------------------------------------------------- 20 | 21 | const contracts = require('./contracts.json'); 22 | 23 | module.exports = contracts; 24 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require('./Migrations.sol'); 2 | 3 | module.exports = (deployer) => { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@openst/brandedtoken-contracts", 3 | "version": "0.10.0", 4 | "description": "BrandedToken Contracts provides token and related smart contracts for token economies.", 5 | "keywords": [ 6 | "OpenST", 7 | "OST", 8 | "Simple Token", 9 | "Token Economy", 10 | "Ethereum", 11 | "EIP20", 12 | "Branded Token" 13 | ], 14 | "homepage": "https://openst.org", 15 | "author": "OpenST Limited", 16 | "license": "Apache-2.0", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/OpenST/brandedtoken-contracts.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/OpenST/brandedtoken-contracts/issues" 23 | }, 24 | "scripts": { 25 | "build-package": "node tools/build_package.js", 26 | "compile-all": "truffle compile --all", 27 | "test": "truffle test", 28 | "test:range": "./tools/test_range.sh", 29 | "prepack": "npm run compile-all && npm run build-package", 30 | "lint": "eslint migrations/*.js test/*/*.js tools/*.js -c .eslintrc" 31 | }, 32 | "main": "dist/index.js", 33 | "files": [ 34 | "dist" 35 | ], 36 | "devDependencies": { 37 | "abi-decoder": "1.2.0", 38 | "assert": "1.4.1", 39 | "bignumber.js": "4.1.0", 40 | "bn.js": "4.11.8", 41 | "eslint": "^5.16.0", 42 | "eslint-config-airbnb-base": "13.1.0", 43 | "eslint-plugin-import": "2.14.0", 44 | "ethereumjs-util": "5.2.0", 45 | "ganache-cli": "6.4.3", 46 | "solidity-coverage": "0.5.11", 47 | "truffle": "5.0.19", 48 | "web3": "1.0.0-beta.36", 49 | "openzeppelin-solidity": "2.1.1" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/branded_token/accept_stake_request.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const EthUtils = require('ethereumjs-util'); 20 | const { AccountProvider } = require('../test_lib/utils.js'); 21 | const { Event } = require('../test_lib/event_decoder.js'); 22 | 23 | const web3 = require('../test_lib/web3.js'); 24 | const utils = require('../test_lib/utils'); 25 | const brandedTokenUtils = require('./utils'); 26 | const config = require('../test_lib/config'); 27 | 28 | const BrandedToken = artifacts.require('BrandedToken'); 29 | const EIP20TokenMockPass = artifacts.require('EIP20TokenMockPass'); 30 | const OrganizationMockWorker = artifacts.require('OrganizationMockWorker'); 31 | 32 | contract('BrandedToken::acceptStakeRequest', async () => { 33 | const r = web3.utils.soliditySha3('r'); 34 | const s = web3.utils.soliditySha3('s'); 35 | const v = 0; 36 | 37 | contract('Negative Tests', async (accounts) => { 38 | const accountProvider = new AccountProvider(accounts); 39 | 40 | it('Reverts if stake request not found', async () => { 41 | const { 42 | brandedToken, 43 | } = await brandedTokenUtils.setupBrandedToken( 44 | accountProvider, 45 | ); 46 | 47 | const worker = accountProvider.get(); 48 | const stakeRequestHash = web3.utils.utf8ToHex('stakeRequestHash'); 49 | 50 | await utils.expectRevert( 51 | brandedToken.acceptStakeRequest( 52 | stakeRequestHash, 53 | r, 54 | s, 55 | v, 56 | { from: worker }, 57 | ), 58 | 'Should revert as stake request not found.', 59 | 'Stake request not found.', 60 | ); 61 | }); 62 | 63 | it('Reverts if signer is not a worker', async () => { 64 | const { 65 | brandedToken, 66 | stakeRequestHash, 67 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 68 | accountProvider, 69 | false, // Use OrganizationMockFail 70 | ); 71 | 72 | const worker = accountProvider.get(); 73 | 74 | await utils.expectRevert( 75 | brandedToken.acceptStakeRequest( 76 | stakeRequestHash, 77 | r, 78 | s, 79 | v, 80 | { from: worker }, 81 | ), 82 | 'Should revert as signer is not a worker.', 83 | 'Signer is not a worker.', 84 | ); 85 | }); 86 | }); 87 | 88 | contract('Event', async (accounts) => { 89 | const accountProvider = new AccountProvider(accounts); 90 | 91 | it('Emits StakeRequestAccepted and Transfer events', async () => { 92 | const { 93 | brandedToken, 94 | staker, 95 | stake, 96 | stakeRequestHash, 97 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 98 | accountProvider, 99 | ); 100 | 101 | const worker = accountProvider.get(); 102 | 103 | const transactionResponse = await brandedToken.acceptStakeRequest( 104 | stakeRequestHash, 105 | r, 106 | s, 107 | v, 108 | { from: worker }, 109 | ); 110 | 111 | const mint = await brandedToken.convertToBrandedTokens(stake); 112 | 113 | const events = Event.decodeTransactionResponse( 114 | transactionResponse, 115 | ); 116 | 117 | assert.strictEqual( 118 | events.length, 119 | 2, 120 | ); 121 | 122 | Event.assertEqual(events[0], { 123 | name: 'StakeRequestAccepted', 124 | args: { 125 | _stakeRequestHash: stakeRequestHash, 126 | _staker: staker, 127 | _stake: new BN(stake), 128 | }, 129 | }); 130 | 131 | Event.assertEqual(events[1], { 132 | name: 'Transfer', 133 | args: { 134 | _from: utils.NULL_ADDRESS, 135 | _to: staker, 136 | _value: mint, 137 | }, 138 | }); 139 | }); 140 | }); 141 | 142 | contract('Storage', async (accounts) => { 143 | const accountProvider = new AccountProvider(accounts); 144 | 145 | it('Successfully mints branded tokens', async () => { 146 | const { 147 | brandedToken, 148 | staker, 149 | stake, 150 | stakeRequestHash, 151 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 152 | accountProvider, 153 | ); 154 | 155 | // N.B.: anyone can call acceptStakeRequest 156 | const worker = accountProvider.get(); 157 | 158 | // Contract does not confirm that address returned from ecrecover 159 | // is not a 0 address. Consequently, signature components 160 | // that return a 0 address are OK so long as 161 | // Organization.isWorker returns true for a 0 address 162 | assert.isOk( 163 | await brandedToken.acceptStakeRequest.call( 164 | stakeRequestHash, 165 | r, 166 | s, 167 | v, 168 | { from: worker }, 169 | ), 170 | ); 171 | 172 | await brandedToken.acceptStakeRequest( 173 | stakeRequestHash, 174 | r, 175 | s, 176 | v, 177 | { from: worker }, 178 | ); 179 | 180 | const mint = await brandedToken.convertToBrandedTokens(stake); 181 | 182 | assert.strictEqual( 183 | mint.cmp( 184 | await brandedToken.balanceOf(staker), 185 | ), 186 | 0, 187 | ); 188 | 189 | assert.strictEqual( 190 | mint.cmp( 191 | await brandedToken.totalSupply(), 192 | ), 193 | 0, 194 | ); 195 | }); 196 | 197 | it('Verifies stake request hash signer', async () => { 198 | // Setup organization 199 | const organization = await OrganizationMockWorker.new(); 200 | const worker = accountProvider.get(); 201 | const valueToken = await EIP20TokenMockPass.new( 202 | 'VT', 203 | 'ValueToken', 204 | config.decimals, 205 | ); 206 | 207 | await organization.setWorker(worker, 0); 208 | 209 | // Setup brandedToken 210 | const brandedToken = await BrandedToken.new( 211 | valueToken.address, 212 | 'BT', 213 | 'BrandedToken', 214 | config.decimals, 215 | 35, 216 | 1, 217 | organization.address, 218 | ); 219 | 220 | // Request stake 221 | const stake = 1; 222 | const mint = await brandedToken.convertToBrandedTokens(stake); 223 | const staker = accountProvider.get(); 224 | 225 | await brandedToken.requestStake( 226 | stake, 227 | mint, 228 | { from: staker }, 229 | ); 230 | 231 | const EIP712_DOMAIN_TYPEHASH = web3.utils.soliditySha3( 232 | 'EIP712Domain(address verifyingContract)', 233 | ); 234 | const DOMAIN_SEPARATOR = web3.utils.soliditySha3( 235 | web3.eth.abi.encodeParameters( 236 | ['bytes32', 'address'], 237 | [EIP712_DOMAIN_TYPEHASH, brandedToken.address], 238 | ), 239 | ); 240 | const stakeRequestHash = await brandedToken.stakeRequestHashes(staker); 241 | 242 | // Prepare and sign typed data, for example see: 243 | // https://github.com/ethereum/EIPs/blob/master/assets/eip-712/Example.js 244 | // N.B.: below differs from the example due to sha3's deprecation. See: 245 | // https://github.com/ethereumjs/ethereumjs-util/blob/master/CHANGELOG.md#600---2018-10-08 246 | const typedDataToSign = EthUtils.keccak( 247 | Buffer.concat( 248 | [ 249 | Buffer.from('19', 'hex'), 250 | Buffer.from('01', 'hex'), 251 | EthUtils.toBuffer(DOMAIN_SEPARATOR), 252 | EthUtils.toBuffer(stakeRequestHash), 253 | ], 254 | ), 255 | ); 256 | const privateKey = EthUtils.keccak('signer'); 257 | const signer = EthUtils.privateToAddress(privateKey); 258 | const signature = EthUtils.ecsign( 259 | typedDataToSign, 260 | privateKey, 261 | ); 262 | 263 | // Set signer as a worker 264 | await organization.setWorker(EthUtils.bufferToHex(signer), 0); 265 | 266 | // Fails with incorrect signature components 267 | await utils.expectRevert( 268 | brandedToken.acceptStakeRequest( 269 | stakeRequestHash, 270 | signature.r, // correct 271 | signature.s, // correct 272 | 0, // incorrect 273 | { from: worker }, 274 | ), 275 | 'Should revert as signer is not a worker.', 276 | 'Signer is not a worker.', 277 | ); 278 | 279 | // Passes with correct signature components 280 | assert.isOk( 281 | await brandedToken.acceptStakeRequest.call( 282 | stakeRequestHash, 283 | signature.r, 284 | signature.s, 285 | signature.v, 286 | { from: worker }, 287 | ), 288 | ); 289 | }); 290 | }); 291 | }); 292 | -------------------------------------------------------------------------------- /test/branded_token/constructor.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | 21 | const config = require('../test_lib/config'); 22 | const utils = require('../test_lib/utils'); 23 | 24 | const BrandedToken = artifacts.require('BrandedToken'); 25 | const EIP20TokenMock = artifacts.require('EIP20TokenMock'); 26 | 27 | /** 28 | * Deploys an EIP20TokenMock contract with the provided decimals. 29 | * @param {number} decimals Decimals for token. 30 | * @return {string} valueToken Address of token. 31 | */ 32 | const deployValueToken = async (decimals) => { 33 | const { address: valueToken } = await EIP20TokenMock.new( 34 | 'VT', 35 | 'ValueToken', 36 | decimals, 37 | ); 38 | 39 | return valueToken; 40 | }; 41 | 42 | contract('BrandedToken::constructor', async () => { 43 | contract('Negative Tests', async (accounts) => { 44 | const accountProvider = new AccountProvider(accounts); 45 | 46 | const symbol = 'BT'; 47 | const name = 'BrandedToken'; 48 | const { decimals } = config; 49 | const organization = accountProvider.get(); 50 | 51 | it('Reverts if valueToken is zero', async () => { 52 | const valueToken = utils.NULL_ADDRESS; 53 | const conversionRate = 35; 54 | const conversionRateDecimals = 1; 55 | 56 | await utils.expectRevert( 57 | BrandedToken.new( 58 | valueToken, 59 | symbol, 60 | name, 61 | decimals, 62 | conversionRate, 63 | conversionRateDecimals, 64 | organization, 65 | ), 66 | 'Should revert as valueToken is zero.', 67 | 'ValueToken is zero.', 68 | ); 69 | }); 70 | 71 | it('Reverts if valueToken decimals does not equal brandedToken decimals', async () => { 72 | const valueToken = await deployValueToken(decimals + 1); 73 | 74 | const conversionRate = 35; 75 | const conversionRateDecimals = 1; 76 | 77 | await utils.expectRevert( 78 | BrandedToken.new( 79 | valueToken, 80 | symbol, 81 | name, 82 | decimals, 83 | conversionRate, 84 | conversionRateDecimals, 85 | organization, 86 | ), 87 | 'Should revert as valueToken decimals does not equal brandedToken decimals.', 88 | 'ValueToken decimals does not equal brandedToken decimals.', 89 | ); 90 | }); 91 | 92 | it('Reverts if conversionRate is zero', async () => { 93 | const valueToken = await deployValueToken(decimals); 94 | 95 | const conversionRate = 0; 96 | const conversionRateDecimals = 1; 97 | 98 | await utils.expectRevert( 99 | BrandedToken.new( 100 | valueToken, 101 | symbol, 102 | name, 103 | decimals, 104 | conversionRate, 105 | conversionRateDecimals, 106 | organization, 107 | ), 108 | 'Should revert as conversionRate is zero.', 109 | 'ConversionRate is zero.', 110 | ); 111 | }); 112 | 113 | it('Reverts if conversionRateDecimals is greater than 5', async () => { 114 | const valueToken = await deployValueToken(decimals); 115 | 116 | const conversionRate = 35; 117 | const conversionRateDecimals = 6; 118 | 119 | await utils.expectRevert( 120 | BrandedToken.new( 121 | valueToken, 122 | symbol, 123 | name, 124 | decimals, 125 | conversionRate, 126 | conversionRateDecimals, 127 | organization, 128 | ), 129 | 'Should revert as conversionRateDecimals is greater than 5.', 130 | 'ConversionRateDecimals is greater than 5.', 131 | ); 132 | }); 133 | }); 134 | 135 | contract('Storage', async (accounts) => { 136 | const accountProvider = new AccountProvider(accounts); 137 | 138 | const symbol = 'BT'; 139 | const name = 'BrandedToken'; 140 | const { decimals } = config; 141 | const organization = accountProvider.get(); 142 | 143 | it('Successfully sets state variables', async () => { 144 | const valueToken = await deployValueToken(decimals); 145 | 146 | const conversionRate = 35; 147 | const conversionRateDecimals = 1; 148 | 149 | const brandedToken = await BrandedToken.new( 150 | valueToken, 151 | symbol, 152 | name, 153 | decimals, 154 | conversionRate, 155 | conversionRateDecimals, 156 | organization, 157 | ); 158 | 159 | assert.strictEqual( 160 | (await brandedToken.valueToken()), 161 | valueToken, 162 | ); 163 | 164 | assert.strictEqual( 165 | (await brandedToken.conversionRate()).cmp( 166 | new BN(conversionRate), 167 | ), 168 | 0, 169 | ); 170 | 171 | assert.strictEqual( 172 | (await brandedToken.conversionRateDecimals()).cmp( 173 | new BN(conversionRateDecimals), 174 | ), 175 | 0, 176 | ); 177 | }); 178 | }); 179 | }); 180 | -------------------------------------------------------------------------------- /test/branded_token/convert_to_branded_tokens.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const BrandedTokenUtils = require('./utils.js'); 21 | 22 | contract('BrandedToken::convertToBrandedTokens', async () => { 23 | contract('Returns', async (accounts) => { 24 | it('Correctly converts to branded tokens', async () => { 25 | const accountProvider = new AccountProvider(accounts); 26 | 27 | const { 28 | brandedToken, 29 | } = await BrandedTokenUtils.setupBrandedToken( 30 | accountProvider, 31 | ); 32 | 33 | const conversionRate = await brandedToken.conversionRate(); 34 | const conversionRateDecimals = await brandedToken.conversionRateDecimals(); 35 | 36 | // Conversion without loss 37 | // Depending on the conversion rate, some amounts 38 | // converts without loss; e.g., when conversion is 1:3.5 39 | // - conversionRate == 35 40 | // - conversionRateDecimals == 1 41 | // - 2 --> 7 42 | const valueTokensLossless = new BN(2); 43 | const brandedTokensLossless = await brandedToken 44 | .convertToBrandedTokens(valueTokensLossless); 45 | 46 | assert.strictEqual( 47 | brandedTokensLossless.cmp( 48 | valueTokensLossless 49 | .mul(conversionRate) 50 | .div(new BN(10).pow(conversionRateDecimals)), 51 | ), 52 | 0, 53 | ); 54 | 55 | assert.strictEqual( 56 | brandedTokensLossless.cmp( 57 | new BN(7), 58 | ), 59 | 0, 60 | ); 61 | 62 | // Conversion with loss 63 | // At other amounts of value tokens, there will be loss 64 | // due to Solidity not supportin fixed or floating point 65 | // math; e.g., when conversion is 1:3.5 66 | // - conversionRate == 35 67 | // - conversionRateDecimals == 1 68 | // - 1 --> 3, not 3.5 69 | const valueTokensLoss = new BN(1); 70 | const brandedTokensLoss = await brandedToken 71 | .convertToBrandedTokens(valueTokensLoss); 72 | 73 | assert.strictEqual( 74 | brandedTokensLoss.cmp( 75 | valueTokensLoss 76 | .mul(conversionRate) 77 | .div(new BN(10).pow(conversionRateDecimals)), 78 | ), 79 | 0, 80 | ); 81 | 82 | // 1 converts to 3, not 3.5, so there is a loss 83 | assert.strictEqual( 84 | brandedTokensLoss.cmp( 85 | new BN(3), 86 | ), 87 | 0, 88 | ); 89 | 90 | // N.B.: the potential for and degree of loss 91 | // as indicated above is considered acceptable, 92 | // depending on the number of decimal places (e.g., 18) 93 | }); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/branded_token/convert_to_value_tokens.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const BrandedTokenUtils = require('./utils.js'); 21 | 22 | contract('BrandedToken::convertToValueTokens', async () => { 23 | contract('Returns', async (accounts) => { 24 | it('Correctly converts to value tokens', async () => { 25 | const accountProvider = new AccountProvider(accounts); 26 | 27 | const { 28 | brandedToken, 29 | } = await BrandedTokenUtils.setupBrandedToken( 30 | accountProvider, 31 | ); 32 | 33 | const conversionRate = await brandedToken.conversionRate(); 34 | const conversionRateDecimals = await brandedToken.conversionRateDecimals(); 35 | 36 | // Conversion without loss 37 | // An amount equal to multiples of the conversionRate 38 | // converts without loss; e.g., when conversion is 1:3.5 39 | // - conversionRate == 35 40 | // - conversionRateDecimals == 1 41 | // - 35 --> 10 42 | const brandedTokensLossless = conversionRate; 43 | const valueTokensLossless = await brandedToken 44 | .convertToValueTokens(brandedTokensLossless); 45 | 46 | assert.strictEqual( 47 | valueTokensLossless.cmp( 48 | brandedTokensLossless 49 | .mul(new BN(10).pow(conversionRateDecimals)) 50 | .div(conversionRate), 51 | ), 52 | 0, 53 | ); 54 | 55 | assert.strictEqual( 56 | valueTokensLossless.cmp( 57 | new BN(10), 58 | ), 59 | 0, 60 | ); 61 | 62 | // Conversion with loss 63 | // At other amounts of branded tokens there will be loss 64 | // due to Solidity not supportin fixed or floating point 65 | // math; e.g., when conversion is 1:3.5 66 | // - conversionRate == 35 67 | // - conversionRateDecimals == 1 68 | // - 36 --> 10 value tokens, not 10.2 69 | const brandedTokensLoss = conversionRate.addn(1); 70 | const valueTokensLoss = await brandedToken 71 | .convertToValueTokens(brandedTokensLoss); 72 | 73 | assert.strictEqual( 74 | valueTokensLoss.cmp( 75 | brandedTokensLoss 76 | .mul(new BN(10).pow(conversionRateDecimals)) 77 | .div(conversionRate), 78 | ), 79 | 0, 80 | ); 81 | 82 | // 36 also converts into 10 so there is a loss in the conversion 83 | assert.strictEqual( 84 | valueTokensLoss.cmp( 85 | new BN(10), 86 | ), 87 | 0, 88 | ); 89 | 90 | // N.B.: the potential for and degree of loss 91 | // as indicated above is considered acceptable, 92 | // depending on the number of decimal places (e.g., 18) 93 | }); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/branded_token/lift_all_restrictions.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const { AccountProvider } = require('../test_lib/utils.js'); 19 | 20 | const utils = require('../test_lib/utils'); 21 | const brandedTokenUtils = require('./utils'); 22 | 23 | contract('BrandedToken::liftAllRestrictions', async () => { 24 | contract('Negative Tests', async (accounts) => { 25 | const accountProvider = new AccountProvider(accounts); 26 | 27 | it('Reverts if msg.sender is not the organization', async () => { 28 | const { 29 | brandedToken, 30 | } = await brandedTokenUtils.setupBrandedToken( 31 | accountProvider, 32 | false, 33 | ); 34 | 35 | const nonOrganization = accountProvider.get(); 36 | 37 | await utils.expectRevert( 38 | brandedToken.liftAllRestrictions( 39 | { from: nonOrganization }, 40 | ), 41 | 'Should revert as msg.sender is not the organization.', 42 | 'Only the organization is allowed to call this method.', 43 | ); 44 | }); 45 | }); 46 | 47 | contract('Storage', async (accounts) => { 48 | const accountProvider = new AccountProvider(accounts); 49 | 50 | it('Successfully lifts all restrictions', async () => { 51 | const { 52 | brandedToken, 53 | staker, 54 | worker, 55 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 56 | accountProvider, 57 | ); 58 | 59 | const to = accountProvider.get(); 60 | const brandedTokens = 1; 61 | 62 | await utils.expectRevert( 63 | brandedToken.transfer( 64 | to, 65 | brandedTokens, 66 | { from: staker }, 67 | ), 68 | 'Should revert as msg.sender is restricted.', 69 | 'Msg.sender is restricted.', 70 | ); 71 | 72 | assert.isOk( 73 | await brandedToken.liftAllRestrictions.call( 74 | { from: worker }, 75 | ), 76 | ); 77 | 78 | await brandedToken.liftAllRestrictions( 79 | { from: worker }, 80 | ); 81 | 82 | assert.isNotOk( 83 | await brandedToken.isUnrestricted( 84 | staker, 85 | { from: worker }, 86 | ), 87 | ); 88 | 89 | await brandedToken.transfer( 90 | to, 91 | brandedTokens, 92 | { from: staker }, 93 | ); 94 | }); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /test/branded_token/lift_restriction.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const { AccountProvider } = require('../test_lib/utils.js'); 19 | 20 | const utils = require('../test_lib/utils'); 21 | const brandedTokenUtils = require('./utils'); 22 | 23 | contract('BrandedToken::liftRestriction', async () => { 24 | contract('Negative Tests', async (accounts) => { 25 | const accountProvider = new AccountProvider(accounts); 26 | 27 | it('Reverts if msg.sender is not a worker', async () => { 28 | const { 29 | brandedToken, 30 | } = await brandedTokenUtils.setupBrandedToken( 31 | accountProvider, 32 | false, 33 | ); 34 | 35 | const restrictionLifted = [accountProvider.get()]; 36 | const nonWorker = accountProvider.get(); 37 | 38 | await utils.expectRevert( 39 | brandedToken.liftRestriction( 40 | restrictionLifted, 41 | { from: nonWorker }, 42 | ), 43 | 'Should revert as msg.sender is not a worker.', 44 | 'Only whitelisted workers are allowed to call this method.', 45 | ); 46 | }); 47 | }); 48 | 49 | contract('Storage', async (accounts) => { 50 | const accountProvider = new AccountProvider(accounts); 51 | 52 | it('Successfully lifts restrictions', async () => { 53 | const { 54 | brandedToken, 55 | } = await brandedTokenUtils.setupBrandedToken( 56 | accountProvider, 57 | ); 58 | 59 | const restrictionLifted = [accountProvider.get(), accountProvider.get()]; 60 | const worker = accountProvider.get(); 61 | 62 | assert.isOk( 63 | await brandedToken.liftRestriction.call( 64 | restrictionLifted, 65 | { from: worker }, 66 | ), 67 | ); 68 | 69 | await brandedToken.liftRestriction( 70 | restrictionLifted, 71 | { from: worker }, 72 | ); 73 | 74 | /* eslint-disable no-restricted-syntax, no-await-in-loop */ 75 | for (const actor of restrictionLifted) { 76 | assert.isOk( 77 | await brandedToken.isUnrestricted( 78 | actor, 79 | ), 80 | ); 81 | } 82 | /* eslint-enable no-restricted-syntax, no-await-in-loop */ 83 | }); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /test/branded_token/redeem.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | 22 | const utils = require('../test_lib/utils'); 23 | const brandedTokenUtils = require('./utils'); 24 | 25 | contract('BrandedToken::redeem', async () => { 26 | contract('Negative Tests', async (accounts) => { 27 | const accountProvider = new AccountProvider(accounts); 28 | 29 | it('Fails if valueToken.transfer returns false', async () => { 30 | const { 31 | brandedToken, 32 | } = await brandedTokenUtils.setupBrandedToken( 33 | accountProvider, 34 | true, 35 | false, // Use EIP20TokenMockPassFail 36 | ); 37 | 38 | await utils.expectRevert( 39 | brandedToken.redeem( 40 | 0, 41 | { from: accountProvider.get() }, 42 | ), 43 | 'Should revert as valueToken.transfer returned false.', 44 | 'ValueToken.transfer returned false.', 45 | ); 46 | }); 47 | }); 48 | 49 | contract('Event', async (accounts) => { 50 | const accountProvider = new AccountProvider(accounts); 51 | 52 | it('Emits Redeemed and Transfer events', async () => { 53 | const { 54 | brandedToken, 55 | staker, 56 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 57 | accountProvider, 58 | ); 59 | 60 | // At a conversion rate of 3.5, 4 branded tokens (least divisible unit) 61 | // evaluates to 1 value token (least divisible unit) 62 | const brandedTokens = 4; 63 | 64 | const transactionResponse = await brandedToken.redeem( 65 | brandedTokens, 66 | { from: staker }, 67 | ); 68 | 69 | const events = Event.decodeTransactionResponse( 70 | transactionResponse, 71 | ); 72 | 73 | assert.strictEqual( 74 | events.length, 75 | 2, 76 | ); 77 | 78 | Event.assertEqual(events[0], { 79 | name: 'Redeemed', 80 | args: { 81 | _redeemer: staker, 82 | _valueTokens: await brandedToken.convertToValueTokens(brandedTokens), 83 | }, 84 | }); 85 | 86 | Event.assertEqual(events[1], { 87 | name: 'Transfer', 88 | args: { 89 | _from: staker, 90 | _to: utils.NULL_ADDRESS, 91 | _value: new BN(brandedTokens), 92 | }, 93 | }); 94 | }); 95 | }); 96 | 97 | contract('Storage', async (accounts) => { 98 | const accountProvider = new AccountProvider(accounts); 99 | 100 | it('Successfully redeems branded tokens', async () => { 101 | const { 102 | brandedToken, 103 | staker, 104 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 105 | accountProvider, 106 | ); 107 | 108 | // At a conversion rate of 3.5, 4 branded tokens (least divisible unit) 109 | // evaluates to 1 value token (least divisible unit) 110 | const brandedTokens = 4; 111 | const totalSupplyBefore = await brandedToken.totalSupply(); 112 | const balanceBefore = await brandedToken.balanceOf(staker); 113 | 114 | assert.isOk( 115 | await brandedToken.redeem.call( 116 | brandedTokens, 117 | { from: staker }, 118 | ), 119 | ); 120 | 121 | await brandedToken.redeem( 122 | brandedTokens, 123 | { from: staker }, 124 | ); 125 | 126 | const totalSupplyAfter = await brandedToken.totalSupply(); 127 | const balanceAfter = await brandedToken.balanceOf(staker); 128 | 129 | assert.strictEqual( 130 | totalSupplyAfter.cmp( 131 | totalSupplyBefore.subn(brandedTokens), 132 | ), 133 | 0, 134 | ); 135 | 136 | assert.strictEqual( 137 | balanceAfter.cmp( 138 | balanceBefore.subn(brandedTokens), 139 | ), 140 | 0, 141 | ); 142 | }); 143 | }); 144 | }); 145 | -------------------------------------------------------------------------------- /test/branded_token/reject_stake_request.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | 22 | const web3 = require('../test_lib/web3.js'); 23 | const utils = require('../test_lib/utils'); 24 | const brandedTokenUtils = require('./utils'); 25 | 26 | contract('BrandedToken::rejectStakeRequest', async () => { 27 | contract('Negative Tests', async (accounts) => { 28 | const accountProvider = new AccountProvider(accounts); 29 | 30 | it('Reverts if msg.sender is not a worker', async () => { 31 | const { 32 | brandedToken, 33 | stakeRequestHash, 34 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 35 | accountProvider, 36 | false, // Use OrganizationMockFail 37 | ); 38 | 39 | const nonWorker = accountProvider.get(); 40 | 41 | await utils.expectRevert( 42 | brandedToken.rejectStakeRequest( 43 | stakeRequestHash, 44 | { from: nonWorker }, 45 | ), 46 | 'Should revert as msg.sender is not a worker.', 47 | 'Only whitelisted workers are allowed to call this method.', 48 | ); 49 | }); 50 | 51 | it('Reverts if stake request not found', async () => { 52 | const { 53 | brandedToken, 54 | } = await brandedTokenUtils.setupBrandedToken( 55 | accountProvider, 56 | ); 57 | 58 | const worker = accountProvider.get(); 59 | const stakeRequestHash = web3.utils.utf8ToHex('stakeRequestHash'); 60 | 61 | await utils.expectRevert( 62 | brandedToken.rejectStakeRequest( 63 | stakeRequestHash, 64 | { from: worker }, 65 | ), 66 | 'Should revert as stake request not found.', 67 | 'Stake request not found.', 68 | ); 69 | }); 70 | 71 | it('Reverts if valueToken.transfer returns false', async () => { 72 | const { 73 | brandedToken, 74 | stakeRequestHash, 75 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 76 | accountProvider, 77 | true, 78 | false, // Use EIP20TokenMockPassFail 79 | ); 80 | 81 | const worker = accountProvider.get(); 82 | 83 | await utils.expectRevert( 84 | brandedToken.rejectStakeRequest( 85 | stakeRequestHash, 86 | { from: worker }, 87 | ), 88 | 'Should revert as valueToken.transfer returned false.', 89 | 'ValueToken.transfer returned false.', 90 | ); 91 | }); 92 | }); 93 | 94 | contract('Event', async (accounts) => { 95 | const accountProvider = new AccountProvider(accounts); 96 | 97 | it('Emits StakeRequestRejected', async () => { 98 | const { 99 | brandedToken, 100 | staker, 101 | stake, 102 | stakeRequestHash, 103 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 104 | accountProvider, 105 | ); 106 | 107 | const worker = accountProvider.get(); 108 | 109 | const transactionResponse = await brandedToken.rejectStakeRequest( 110 | stakeRequestHash, 111 | { from: worker }, 112 | ); 113 | 114 | const events = Event.decodeTransactionResponse( 115 | transactionResponse, 116 | ); 117 | 118 | assert.strictEqual( 119 | events.length, 120 | 1, 121 | ); 122 | 123 | Event.assertEqual(events[0], { 124 | name: 'StakeRequestRejected', 125 | args: { 126 | _stakeRequestHash: stakeRequestHash, 127 | _staker: staker, 128 | _stake: new BN(stake), 129 | }, 130 | }); 131 | }); 132 | }); 133 | 134 | contract('Storage', async (accounts) => { 135 | const accountProvider = new AccountProvider(accounts); 136 | 137 | it('Successfully revokes stake request', async () => { 138 | const { 139 | brandedToken, 140 | staker, 141 | stakeRequestHash, 142 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 143 | accountProvider, 144 | ); 145 | 146 | const worker = accountProvider.get(); 147 | 148 | assert.isOk( 149 | await brandedToken.rejectStakeRequest.call( 150 | stakeRequestHash, 151 | { from: worker }, 152 | ), 153 | ); 154 | 155 | await brandedToken.rejectStakeRequest( 156 | stakeRequestHash, 157 | { from: worker }, 158 | ); 159 | 160 | assert.strictEqual( 161 | await brandedToken.stakeRequestHashes(staker), 162 | utils.NULL_BYTES32, 163 | ); 164 | 165 | const stakeRequest = await brandedToken.stakeRequests(stakeRequestHash); 166 | 167 | assert.strictEqual( 168 | stakeRequest.staker, 169 | utils.NULL_ADDRESS, 170 | ); 171 | 172 | assert.strictEqual( 173 | stakeRequest.stake.cmp( 174 | new BN(0), 175 | ), 176 | 0, 177 | ); 178 | 179 | assert.strictEqual( 180 | stakeRequest.nonce.cmp( 181 | new BN(0), 182 | ), 183 | 0, 184 | ); 185 | }); 186 | }); 187 | }); 188 | -------------------------------------------------------------------------------- /test/branded_token/request_stake.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | 22 | const web3 = require('../test_lib/web3.js'); 23 | const utils = require('../test_lib/utils'); 24 | const brandedTokenUtils = require('./utils'); 25 | const config = require('../test_lib/config'); 26 | 27 | const BrandedToken = artifacts.require('BrandedToken'); 28 | const EIP20TokenMockFail = artifacts.require('EIP20TokenMockFail'); 29 | 30 | contract('BrandedToken::requestStake', async () => { 31 | contract('Negative Tests', async (accounts) => { 32 | const accountProvider = new AccountProvider(accounts); 33 | 34 | it('Reverts if mint is not equivalent to stake', async () => { 35 | const { 36 | brandedToken, 37 | } = await brandedTokenUtils.setupBrandedToken( 38 | accountProvider, 39 | ); 40 | 41 | const stake = 1; 42 | const mint = 0; 43 | const staker = accountProvider.get(); 44 | 45 | await utils.expectRevert( 46 | brandedToken.requestStake( 47 | stake, 48 | mint, 49 | { from: staker }, 50 | ), 51 | 'Should revert as mint is not equivalent to stake.', 52 | 'Mint is not equivalent to stake.', 53 | ); 54 | }); 55 | 56 | it('Reverts if staker has a stake request hash', async () => { 57 | const { 58 | brandedToken, 59 | } = await brandedTokenUtils.setupBrandedToken( 60 | accountProvider, 61 | ); 62 | 63 | const stake = 1; 64 | const mint = await brandedToken.convertToBrandedTokens(stake); 65 | const staker = accountProvider.get(); 66 | 67 | await brandedToken.requestStake( 68 | stake, 69 | mint, 70 | { from: staker }, 71 | ); 72 | 73 | await utils.expectRevert( 74 | brandedToken.requestStake( 75 | stake, 76 | mint, 77 | { from: staker }, 78 | ), 79 | 'Should revert as staker has a stake request hash.', 80 | 'Staker has a stake request hash.', 81 | ); 82 | }); 83 | 84 | it('Reverts if valueToken.transferFrom returns false', async () => { 85 | const valueToken = await EIP20TokenMockFail.new( 86 | 'VT', 87 | 'ValueToken', 88 | config.decimals, 89 | ); 90 | 91 | const brandedToken = await BrandedToken.new( 92 | valueToken.address, 93 | 'BT', 94 | 'BrandedToken', 95 | config.decimals, 96 | 35, 97 | 1, 98 | await accountProvider.get(), 99 | ); 100 | 101 | const stake = 1; 102 | const mint = await brandedToken.convertToBrandedTokens(stake); 103 | const staker = accountProvider.get(); 104 | 105 | await utils.expectRevert( 106 | brandedToken.requestStake( 107 | stake, 108 | mint, 109 | { from: staker }, 110 | ), 111 | 'Should revert as valueToken.transferFrom returned false.', 112 | 'ValueToken.transferFrom returned false.', 113 | ); 114 | }); 115 | }); 116 | 117 | contract('Event', async (accounts) => { 118 | const accountProvider = new AccountProvider(accounts); 119 | 120 | 121 | it('Emits StakeRequested event.', async () => { 122 | const { 123 | brandedToken, 124 | } = await brandedTokenUtils.setupBrandedToken( 125 | accountProvider, 126 | ); 127 | 128 | const stake = 1; 129 | const mint = await brandedToken.convertToBrandedTokens(stake); 130 | const staker = accountProvider.get(); 131 | 132 | const transactionResponse = await brandedToken.requestStake( 133 | stake, 134 | mint, 135 | { from: staker }, 136 | ); 137 | 138 | const events = Event.decodeTransactionResponse( 139 | transactionResponse, 140 | ); 141 | 142 | assert.strictEqual( 143 | events.length, 144 | 1, 145 | ); 146 | 147 | Event.assertEqual(events[0], { 148 | name: 'StakeRequested', 149 | args: { 150 | _stakeRequestHash: await brandedToken.stakeRequestHashes(staker), 151 | _staker: staker, 152 | _stake: new BN(stake), 153 | // global nonce is incremented after assignment to a stake request 154 | _nonce: (await brandedToken.nonce()).subn(1), 155 | }, 156 | }); 157 | }); 158 | }); 159 | 160 | contract('Storage', async (accounts) => { 161 | const accountProvider = new AccountProvider(accounts); 162 | 163 | it('Successfully stores stake request data', async () => { 164 | const { 165 | brandedToken, 166 | } = await brandedTokenUtils.setupBrandedToken( 167 | accountProvider, 168 | ); 169 | 170 | const stake = 1; 171 | const mint = await brandedToken.convertToBrandedTokens(stake); 172 | const staker = accountProvider.get(); 173 | 174 | const stakeRequestHash = await brandedToken.requestStake.call( 175 | stake, 176 | mint, 177 | { from: staker }, 178 | ); 179 | 180 | await brandedToken.requestStake( 181 | stake, 182 | mint, 183 | { from: staker }, 184 | ); 185 | 186 | assert.strictEqual( 187 | stakeRequestHash, 188 | await brandedToken.stakeRequestHashes(staker), 189 | ); 190 | 191 | const stakeRequest = await brandedToken.stakeRequests(stakeRequestHash); 192 | 193 | assert.strictEqual( 194 | stakeRequest.staker, 195 | staker, 196 | ); 197 | 198 | assert.strictEqual( 199 | stakeRequest.stake.cmp( 200 | new BN(stake), 201 | ), 202 | 0, 203 | ); 204 | 205 | assert.strictEqual( 206 | stakeRequest.nonce.cmp( 207 | // global nonce is incremented after assignment to a stake request 208 | (await brandedToken.nonce()).subn(1), 209 | ), 210 | 0, 211 | ); 212 | }); 213 | 214 | it('Calculates stakeRequestHash per EIP 712', async () => { 215 | const { 216 | brandedToken, 217 | stakeRequestHash, 218 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 219 | accountProvider, 220 | ); 221 | 222 | const BT_STAKE_REQUEST_TYPEHASH = web3.utils.soliditySha3( 223 | 'StakeRequest(address staker,uint256 stake,uint256 nonce)', 224 | ); 225 | const stakeRequest = await brandedToken.stakeRequests(stakeRequestHash); 226 | const calculatedHash = web3.utils.soliditySha3( 227 | web3.eth.abi.encodeParameters( 228 | [ 229 | 'bytes32', 230 | 'address', 231 | 'uint256', 232 | 'uint256', 233 | ], 234 | [ 235 | BT_STAKE_REQUEST_TYPEHASH, 236 | stakeRequest.staker, 237 | stakeRequest.stake.toNumber(), 238 | stakeRequest.nonce.toNumber(), 239 | ], 240 | ), 241 | ); 242 | 243 | assert.strictEqual( 244 | calculatedHash, 245 | stakeRequestHash, 246 | ); 247 | }); 248 | }); 249 | }); 250 | -------------------------------------------------------------------------------- /test/branded_token/revoke_stake_request.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | 22 | const utils = require('../test_lib/utils'); 23 | const brandedTokenUtils = require('./utils'); 24 | 25 | contract('BrandedToken::revokeStakeRequest', async () => { 26 | contract('Negative Tests', async (accounts) => { 27 | const accountProvider = new AccountProvider(accounts); 28 | 29 | it('Reverts if msg.sender is not staker', async () => { 30 | const { 31 | brandedToken, 32 | stakeRequestHash, 33 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 34 | accountProvider, 35 | ); 36 | 37 | const nonStaker = accountProvider.get(); 38 | 39 | await utils.expectRevert( 40 | brandedToken.revokeStakeRequest( 41 | stakeRequestHash, 42 | { from: nonStaker }, 43 | ), 44 | 'Should revert as msg.sender is not staker.', 45 | 'Msg.sender is not staker.', 46 | ); 47 | }); 48 | 49 | it('Reverts if valueToken.transfer returns false', async () => { 50 | const { 51 | brandedToken, 52 | staker, 53 | stakeRequestHash, 54 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 55 | accountProvider, 56 | true, 57 | false, // Use EIP20TokenMockPassFail 58 | ); 59 | 60 | await utils.expectRevert( 61 | brandedToken.revokeStakeRequest( 62 | stakeRequestHash, 63 | { from: staker }, 64 | ), 65 | 'Should revert as valueToken.transfer returned false.', 66 | 'ValueToken.transfer returned false.', 67 | ); 68 | }); 69 | }); 70 | 71 | contract('Event', async (accounts) => { 72 | const accountProvider = new AccountProvider(accounts); 73 | 74 | it('Emits StakeRequestRevoked event', async () => { 75 | const { 76 | brandedToken, 77 | staker, 78 | stake, 79 | stakeRequestHash, 80 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 81 | accountProvider, 82 | ); 83 | 84 | const transactionResponse = await brandedToken.revokeStakeRequest( 85 | stakeRequestHash, 86 | { from: staker }, 87 | ); 88 | 89 | const events = Event.decodeTransactionResponse( 90 | transactionResponse, 91 | ); 92 | 93 | assert.strictEqual( 94 | events.length, 95 | 1, 96 | ); 97 | 98 | Event.assertEqual(events[0], { 99 | name: 'StakeRequestRevoked', 100 | args: { 101 | _stakeRequestHash: stakeRequestHash, 102 | _staker: staker, 103 | _stake: new BN(stake), 104 | }, 105 | }); 106 | }); 107 | }); 108 | 109 | contract('Storage', async (accounts) => { 110 | const accountProvider = new AccountProvider(accounts); 111 | 112 | it('Successfully revokes stake request', async () => { 113 | const { 114 | brandedToken, 115 | staker, 116 | stakeRequestHash, 117 | } = await brandedTokenUtils.setupBrandedTokenAndStakeRequest( 118 | accountProvider, 119 | ); 120 | 121 | assert.isOk( 122 | await brandedToken.revokeStakeRequest.call( 123 | stakeRequestHash, 124 | { from: staker }, 125 | ), 126 | ); 127 | 128 | await brandedToken.revokeStakeRequest( 129 | stakeRequestHash, 130 | { from: staker }, 131 | ); 132 | 133 | assert.strictEqual( 134 | await brandedToken.stakeRequestHashes(staker), 135 | utils.NULL_BYTES32, 136 | ); 137 | 138 | const stakeRequest = await brandedToken.stakeRequests(stakeRequestHash); 139 | 140 | assert.strictEqual( 141 | stakeRequest.staker, 142 | utils.NULL_ADDRESS, 143 | ); 144 | 145 | assert.strictEqual( 146 | stakeRequest.stake.cmp( 147 | new BN(0), 148 | ), 149 | 0, 150 | ); 151 | 152 | assert.strictEqual( 153 | stakeRequest.nonce.cmp( 154 | new BN(0), 155 | ), 156 | 0, 157 | ); 158 | }); 159 | }); 160 | }); 161 | -------------------------------------------------------------------------------- /test/branded_token/set_name.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const { AccountProvider } = require('../test_lib/utils.js'); 19 | const { Event } = require('../test_lib/event_decoder.js'); 20 | 21 | const utils = require('../test_lib/utils'); 22 | const brandedTokenUtils = require('./utils'); 23 | 24 | contract('BrandedToken::setName', async () => { 25 | const newName = 'New BrandedToken'; 26 | 27 | contract('Negative Tests', async (accounts) => { 28 | const accountProvider = new AccountProvider(accounts); 29 | 30 | it('Reverts if msg.sender is not a worker', async () => { 31 | const { 32 | brandedToken, 33 | } = await brandedTokenUtils.setupBrandedToken( 34 | accountProvider, 35 | false, 36 | ); 37 | 38 | const nonWorker = accountProvider.get(); 39 | 40 | await utils.expectRevert( 41 | brandedToken.setName( 42 | newName, 43 | { from: nonWorker }, 44 | ), 45 | 'Should revert as msg.sender is not a worker.', 46 | 'Only whitelisted workers are allowed to call this method.', 47 | ); 48 | }); 49 | }); 50 | 51 | contract('Event', async (accounts) => { 52 | const accountProvider = new AccountProvider(accounts); 53 | 54 | it('Emits NameSet event', async () => { 55 | const { 56 | brandedToken, 57 | } = await brandedTokenUtils.setupBrandedToken( 58 | accountProvider, 59 | ); 60 | 61 | const worker = accountProvider.get(); 62 | 63 | const transactionResponse = await brandedToken.setName( 64 | newName, 65 | { from: worker }, 66 | ); 67 | 68 | const events = Event.decodeTransactionResponse( 69 | transactionResponse, 70 | ); 71 | 72 | assert.strictEqual( 73 | events.length, 74 | 1, 75 | ); 76 | 77 | Event.assertEqual(events[0], { 78 | name: 'NameSet', 79 | args: { 80 | _name: newName, 81 | }, 82 | }); 83 | }); 84 | }); 85 | 86 | contract('Storage', async (accounts) => { 87 | const accountProvider = new AccountProvider(accounts); 88 | 89 | it('Successfully sets name', async () => { 90 | const { 91 | brandedToken, 92 | } = await brandedTokenUtils.setupBrandedToken( 93 | accountProvider, 94 | ); 95 | 96 | const worker = accountProvider.get(); 97 | 98 | assert.isOk( 99 | await brandedToken.setName.call( 100 | newName, 101 | { from: worker }, 102 | ), 103 | ); 104 | 105 | await brandedToken.setName( 106 | newName, 107 | { from: worker }, 108 | ); 109 | 110 | assert.strictEqual( 111 | newName, 112 | await brandedToken.name(), 113 | ); 114 | }); 115 | }); 116 | }); 117 | -------------------------------------------------------------------------------- /test/branded_token/set_symbol.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const { AccountProvider } = require('../test_lib/utils.js'); 19 | const { Event } = require('../test_lib/event_decoder.js'); 20 | 21 | const utils = require('../test_lib/utils'); 22 | const brandedTokenUtils = require('./utils'); 23 | 24 | contract('BrandedToken::setSymbol', async () => { 25 | const newSymbol = 'NBT'; 26 | 27 | contract('Negative Tests', async (accounts) => { 28 | const accountProvider = new AccountProvider(accounts); 29 | 30 | it('Reverts if msg.sender is not a worker', async () => { 31 | const { 32 | brandedToken, 33 | } = await brandedTokenUtils.setupBrandedToken( 34 | accountProvider, 35 | false, 36 | ); 37 | 38 | const nonWorker = accountProvider.get(); 39 | 40 | await utils.expectRevert( 41 | brandedToken.setSymbol( 42 | newSymbol, 43 | { from: nonWorker }, 44 | ), 45 | 'Should revert as msg.sender is not a worker.', 46 | 'Only whitelisted workers are allowed to call this method.', 47 | ); 48 | }); 49 | }); 50 | 51 | contract('Event', async (accounts) => { 52 | const accountProvider = new AccountProvider(accounts); 53 | 54 | it('Emits SymbolSet event', async () => { 55 | const { 56 | brandedToken, 57 | } = await brandedTokenUtils.setupBrandedToken( 58 | accountProvider, 59 | ); 60 | 61 | const worker = accountProvider.get(); 62 | 63 | const transactionResponse = await brandedToken.setSymbol( 64 | newSymbol, 65 | { from: worker }, 66 | ); 67 | 68 | const events = Event.decodeTransactionResponse( 69 | transactionResponse, 70 | ); 71 | 72 | assert.strictEqual( 73 | events.length, 74 | 1, 75 | ); 76 | 77 | Event.assertEqual(events[0], { 78 | name: 'SymbolSet', 79 | args: { 80 | _symbol: newSymbol, 81 | }, 82 | }); 83 | }); 84 | }); 85 | 86 | contract('Storage', async (accounts) => { 87 | const accountProvider = new AccountProvider(accounts); 88 | 89 | it('Successfully sets symbol', async () => { 90 | const { 91 | brandedToken, 92 | } = await brandedTokenUtils.setupBrandedToken( 93 | accountProvider, 94 | ); 95 | 96 | const worker = accountProvider.get(); 97 | 98 | assert.isOk( 99 | await brandedToken.setSymbol.call( 100 | newSymbol, 101 | { from: worker }, 102 | ), 103 | ); 104 | 105 | await brandedToken.setSymbol( 106 | newSymbol, 107 | { from: worker }, 108 | ); 109 | 110 | assert.strictEqual( 111 | newSymbol, 112 | await brandedToken.symbol(), 113 | ); 114 | }); 115 | }); 116 | }); 117 | -------------------------------------------------------------------------------- /test/branded_token/transfer.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const { AccountProvider } = require('../test_lib/utils.js'); 19 | 20 | const utils = require('../test_lib/utils'); 21 | const brandedTokenUtils = require('./utils'); 22 | 23 | contract('BrandedToken::transfer', async () => { 24 | contract('Negative Tests', async (accounts) => { 25 | const accountProvider = new AccountProvider(accounts); 26 | 27 | it('Reverts if msg.sender is restricted', async () => { 28 | const { 29 | brandedToken, 30 | staker, 31 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 32 | accountProvider, 33 | ); 34 | 35 | const to = accountProvider.get(); 36 | const brandedTokens = 1; 37 | 38 | await utils.expectRevert( 39 | brandedToken.transfer( 40 | to, 41 | brandedTokens, 42 | { from: staker }, 43 | ), 44 | 'Should revert as msg.sender is restricted.', 45 | 'Msg.sender is restricted.', 46 | ); 47 | }); 48 | }); 49 | 50 | contract('Storage', async (accounts) => { 51 | const accountProvider = new AccountProvider(accounts); 52 | 53 | it('Successfully transfers branded tokens', async () => { 54 | const { 55 | brandedToken, 56 | staker, 57 | worker, 58 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 59 | accountProvider, 60 | ); 61 | 62 | const to = accountProvider.get(); 63 | const brandedTokens = 1; 64 | const restrictionLifted = [staker]; 65 | 66 | await brandedToken.liftRestriction( 67 | restrictionLifted, 68 | { from: worker }, 69 | ); 70 | 71 | assert.isOk( 72 | await brandedToken.transfer.call( 73 | to, 74 | brandedTokens, 75 | { from: staker }, 76 | ), 77 | ); 78 | 79 | await brandedToken.transfer( 80 | to, 81 | brandedTokens, 82 | { from: staker }, 83 | ); 84 | }); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /test/branded_token/transferFrom.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const { AccountProvider } = require('../test_lib/utils.js'); 19 | 20 | const utils = require('../test_lib/utils'); 21 | const brandedTokenUtils = require('./utils'); 22 | 23 | contract('BrandedToken::transferFrom', async () => { 24 | contract('Negative Tests', async (accounts) => { 25 | const accountProvider = new AccountProvider(accounts); 26 | 27 | it('Reverts if msg.sender is restricted', async () => { 28 | const { 29 | brandedToken, 30 | staker, 31 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 32 | accountProvider, 33 | ); 34 | 35 | const actor = accountProvider.get(); 36 | const to = accountProvider.get(); 37 | const brandedTokens = 1; 38 | 39 | await brandedToken.approve( 40 | actor, 41 | brandedTokens, 42 | { from: staker }, 43 | ); 44 | 45 | await utils.expectRevert( 46 | brandedToken.transferFrom( 47 | staker, 48 | to, 49 | brandedTokens, 50 | { from: actor }, 51 | ), 52 | 'Should revert as msg.sender is restricted.', 53 | 'Msg.sender is restricted.', 54 | ); 55 | }); 56 | }); 57 | 58 | contract('Storage', async (accounts) => { 59 | const accountProvider = new AccountProvider(accounts); 60 | 61 | it('Successfully transfers branded tokens', async () => { 62 | const { 63 | brandedToken, 64 | staker, 65 | worker, 66 | } = await brandedTokenUtils.setupBrandedTokenAndAcceptedStakeRequest( 67 | accountProvider, 68 | ); 69 | 70 | const actor = accountProvider.get(); 71 | const to = accountProvider.get(); 72 | const brandedTokens = 1; 73 | 74 | await brandedToken.approve( 75 | actor, 76 | brandedTokens, 77 | { from: staker }, 78 | ); 79 | 80 | const restrictionLifted = [actor]; 81 | 82 | await brandedToken.liftRestriction( 83 | restrictionLifted, 84 | { from: worker }, 85 | ); 86 | 87 | assert.isOk( 88 | await brandedToken.transferFrom.call( 89 | staker, 90 | to, 91 | brandedTokens, 92 | { from: actor }, 93 | ), 94 | ); 95 | 96 | await brandedToken.transferFrom( 97 | staker, 98 | to, 99 | brandedTokens, 100 | { from: actor }, 101 | ); 102 | }); 103 | }); 104 | }); 105 | -------------------------------------------------------------------------------- /test/branded_token/utils.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OST.com Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const config = require('../test_lib/config'); 19 | const web3 = require('../test_lib/web3.js'); 20 | 21 | const BrandedToken = artifacts.require('BrandedToken'); 22 | const EIP20TokenMockPass = artifacts.require('EIP20TokenMockPass'); 23 | const EIP20TokenMockPassFail = artifacts.require('EIP20TokenMockPassFail'); 24 | const OrganizationMockPass = artifacts.require('OrganizationMockPass'); 25 | const OrganizationMockFail = artifacts.require('OrganizationMockFail'); 26 | 27 | /** 28 | * Sets up a BrandedToken. 29 | */ 30 | module.exports.setupBrandedToken = async ( 31 | accountProvider, 32 | useOrganizationMockPass = true, 33 | useEIP20TokenMockPass = true, 34 | ) => { 35 | const symbol = 'BT'; 36 | const name = 'BrandedToken'; 37 | const { decimals } = config; 38 | const conversionRate = 35; 39 | const conversionRateDecimals = 1; 40 | 41 | const valueToken = await ( 42 | useEIP20TokenMockPass 43 | ? EIP20TokenMockPass.new('VT', 'ValueToken', decimals) 44 | : EIP20TokenMockPassFail.new('VT', 'ValueToken', decimals) 45 | ); 46 | const organization = await ( 47 | useOrganizationMockPass 48 | ? OrganizationMockPass.new() 49 | : OrganizationMockFail.new() 50 | ); 51 | 52 | const brandedToken = await BrandedToken.new( 53 | valueToken.address, 54 | symbol, 55 | name, 56 | decimals, 57 | conversionRate, 58 | conversionRateDecimals, 59 | organization.address, 60 | ); 61 | 62 | return { 63 | brandedToken, 64 | }; 65 | }; 66 | 67 | /** 68 | * Sets up a BrandedToken and a stake request. 69 | */ 70 | module.exports.setupBrandedTokenAndStakeRequest = async ( 71 | accountProvider, 72 | useOrganizationMockPass = true, 73 | useEIP20TokenMockPass = true, 74 | ) => { 75 | const { 76 | brandedToken, 77 | } = await this.setupBrandedToken( 78 | accountProvider, 79 | useOrganizationMockPass, 80 | useEIP20TokenMockPass, 81 | ); 82 | 83 | const staker = accountProvider.get(); 84 | const stake = 2; 85 | const mint = await brandedToken.convertToBrandedTokens(stake); 86 | 87 | const stakeRequestHash = await brandedToken.requestStake.call( 88 | stake, 89 | mint, 90 | { from: staker }, 91 | ); 92 | 93 | await brandedToken.requestStake( 94 | stake, 95 | mint, 96 | { from: staker }, 97 | ); 98 | 99 | return { 100 | brandedToken, 101 | staker, 102 | stake, 103 | stakeRequestHash, 104 | }; 105 | }; 106 | 107 | /** 108 | * Sets up a BrandedToken and an accepted stake request. 109 | */ 110 | module.exports.setupBrandedTokenAndAcceptedStakeRequest = async (accountProvider) => { 111 | const { 112 | brandedToken, 113 | staker, 114 | stake, 115 | stakeRequestHash, 116 | } = await this.setupBrandedTokenAndStakeRequest( 117 | accountProvider, 118 | ); 119 | 120 | const r = web3.utils.soliditySha3('r'); 121 | const s = web3.utils.soliditySha3('s'); 122 | const v = 0; 123 | const worker = accountProvider.get(); 124 | 125 | await brandedToken.acceptStakeRequest( 126 | stakeRequestHash, 127 | r, 128 | s, 129 | v, 130 | { from: worker }, 131 | ); 132 | 133 | return { 134 | brandedToken, 135 | staker, 136 | stake, 137 | stakeRequestHash, 138 | worker, 139 | }; 140 | }; 141 | -------------------------------------------------------------------------------- /test/gateway_composer/approve_token.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const utils = require('../test_lib/utils'); 20 | const { AccountProvider } = require('../test_lib/utils.js'); 21 | 22 | const gatewayComposerUtils = require('./utils'); 23 | 24 | contract('GatewayComposer::approveToken', async (accounts) => { 25 | describe('Negative Tests', async () => { 26 | const accountProvider = new AccountProvider(accounts); 27 | 28 | it('Fails when owner is not the caller.', async () => { 29 | const { 30 | gatewayComposer, 31 | valueToken, 32 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 33 | 34 | const spender = accountProvider.get(); 35 | const amount = new BN(10); 36 | await utils.expectRevert(gatewayComposer.approveToken( 37 | valueToken.address, 38 | spender, 39 | amount, 40 | { from: accountProvider.get() }, 41 | ), 42 | 'Should revert as msg.sender is not the owner.', 43 | 'Only owner can call the function.'); 44 | }); 45 | 46 | it('Fails when EIP20 token address is invalid.', async () => { 47 | const { 48 | gatewayComposer, 49 | owner, 50 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 51 | 52 | const to = accountProvider.get(); 53 | const amount = new BN(10); 54 | await utils.expectRevert(gatewayComposer.approveToken( 55 | utils.NULL_ADDRESS, 56 | to, 57 | amount, 58 | { from: owner }, 59 | ), 60 | 'Should revert as token address is null.', 61 | 'EIP20 token address is zero.'); 62 | }); 63 | }); 64 | 65 | describe('Positive Tests', async () => { 66 | const accountProvider = new AccountProvider(accounts); 67 | 68 | it('Returns true on successful execution.', async () => { 69 | const { 70 | gatewayComposer, 71 | valueToken, 72 | owner, 73 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 74 | 75 | const amount = new BN(10); 76 | // Set GatewayComposer address balance. 77 | await valueToken.setBalance(gatewayComposer.address, amount); 78 | const to = accountProvider.get(); 79 | const executionStatus = await gatewayComposer.approveToken.call( 80 | valueToken.address, 81 | to, 82 | amount, 83 | { from: owner }, 84 | ); 85 | assert.strictEqual(executionStatus, true); 86 | }); 87 | 88 | it('Validates destination address allowance after calling approveToken.', async () => { 89 | const { 90 | gatewayComposer, 91 | valueToken, 92 | owner, 93 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 94 | 95 | const amount = new BN(10); 96 | // Set GatewayComposer address balance. 97 | await valueToken.setBalance(gatewayComposer.address, amount); 98 | const to = accountProvider.get(); 99 | await gatewayComposer.approveToken( 100 | valueToken.address, 101 | to, 102 | amount, 103 | { from: owner }, 104 | ); 105 | 106 | const toAllowanceAfter = await valueToken.allowance.call( 107 | gatewayComposer.address, 108 | to, 109 | ); 110 | assert.strictEqual( 111 | toAllowanceAfter.cmp(amount), 112 | 0, 113 | ); 114 | }); 115 | }); 116 | }); 117 | -------------------------------------------------------------------------------- /test/gateway_composer/constructor.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const GatewayComposer = artifacts.require('GatewayComposer'); 19 | 20 | const utils = require('../test_lib/utils'); 21 | 22 | const BrandedToken = artifacts.require('BrandedToken'); 23 | const EIP20TokenMock = artifacts.require('EIP20TokenMock'); 24 | const { AccountProvider } = require('../test_lib/utils.js'); 25 | 26 | /** 27 | * Deploys an EIP20TokenMock contract with the provided decimals. 28 | * @param {number} decimals Decimals for token. 29 | * @return {string} valueToken Address of token. 30 | */ 31 | const deployValueToken = async (decimals) => { 32 | const { address: valueToken } = await EIP20TokenMock.new( 33 | 'VT', 34 | 'ValueToken', 35 | decimals, 36 | ); 37 | 38 | return valueToken; 39 | }; 40 | 41 | contract('GatewayComposer::constructor', async (accounts) => { 42 | describe('Negative Tests', async () => { 43 | let accountProvider; 44 | let deployer; 45 | let owner; 46 | let valueToken; 47 | let brandedToken; 48 | 49 | beforeEach(async () => { 50 | accountProvider = new AccountProvider(accounts); 51 | deployer = accountProvider.get(); 52 | owner = accountProvider.get(); 53 | valueToken = accountProvider.get(); 54 | brandedToken = accountProvider.get(); 55 | }); 56 | 57 | it('Reverts if owner address is zero.', async () => { 58 | await utils.expectRevert(GatewayComposer.new( 59 | utils.NULL_ADDRESS, 60 | valueToken, 61 | brandedToken, 62 | { from: deployer }, 63 | ), 64 | 'It should revert as owner address is zero.', 65 | 'Owner address is zero.'); 66 | }); 67 | 68 | it('Reverts if ValueToken address is zero.', async () => { 69 | await utils.expectRevert(GatewayComposer.new( 70 | owner, 71 | utils.NULL_ADDRESS, 72 | brandedToken, 73 | { from: deployer }, 74 | ), 75 | 'It should revert as ValueToken address is zero.', 76 | 'ValueToken address is zero.'); 77 | }); 78 | 79 | it('Reverts if branded token address is zero.', async () => { 80 | await utils.expectRevert(GatewayComposer.new( 81 | owner, 82 | valueToken, 83 | utils.NULL_ADDRESS, 84 | { from: deployer }, 85 | ), 86 | 'It should revert as BrandedToken address is zero.', 87 | 'BrandedToken address is zero.'); 88 | }); 89 | 90 | it('Reverts if ValueToken address is same as owner address.', async () => { 91 | await utils.expectRevert(GatewayComposer.new( 92 | valueToken, 93 | valueToken, 94 | brandedToken, 95 | { from: deployer }, 96 | ), 97 | 'It should revert as valueToken address is same as owner address.', 98 | 'ValueToken address is same as owner address.'); 99 | }); 100 | 101 | it('Reverts if BrandedToken address is same as owner address.', async () => { 102 | await utils.expectRevert(GatewayComposer.new( 103 | brandedToken, 104 | valueToken, 105 | brandedToken, 106 | { from: deployer }, 107 | ), 108 | 'It should revert as BrandedToken address is same as owner address.', 109 | 'BrandedToken address is same as owner address.'); 110 | }); 111 | 112 | it('Reverts if ValueToken is not equal to BrandedToken.valueToken.', async () => { 113 | const decimals = 5; 114 | 115 | valueToken = await deployValueToken(decimals); 116 | brandedToken = await BrandedToken.new( 117 | valueToken, 118 | 'TST', 119 | 'Test', 120 | decimals, 121 | 10, 122 | 5, 123 | accountProvider.get(), 124 | { from: deployer }, 125 | ); 126 | await utils.expectRevert(GatewayComposer.new( 127 | owner, 128 | accountProvider.get(), 129 | brandedToken.address, 130 | { from: deployer }, 131 | ), 132 | 'It should revert as ValueToken should match BrandedToken.ValueToken.', 133 | 'ValueToken should match BrandedToken.valueToken.'); 134 | }); 135 | }); 136 | 137 | describe('Storage', async () => { 138 | let accountProvider; 139 | let deployer; 140 | let owner; 141 | let valueToken; 142 | let brandedToken; 143 | 144 | beforeEach(async () => { 145 | accountProvider = new AccountProvider(accounts); 146 | deployer = accountProvider.get(); 147 | owner = accountProvider.get(); 148 | const decimals = 5; 149 | 150 | valueToken = await deployValueToken(decimals); 151 | brandedToken = await BrandedToken.new( 152 | valueToken, 153 | 'TST', 154 | 'Test', 155 | decimals, 156 | 10, 157 | 5, 158 | accountProvider.get(), 159 | { from: deployer }, 160 | ); 161 | }); 162 | 163 | it('Sets passed arguments correctly.', async () => { 164 | const gatewayComposer = await GatewayComposer.new( 165 | owner, 166 | valueToken, 167 | brandedToken.address, 168 | { from: deployer }, 169 | ); 170 | 171 | assert.strictEqual(await gatewayComposer.owner.call(), owner); 172 | assert.strictEqual(await gatewayComposer.valueToken.call(), valueToken); 173 | assert.strictEqual( 174 | await gatewayComposer.brandedToken.call(), 175 | brandedToken.address, 176 | ); 177 | }); 178 | }); 179 | }); 180 | -------------------------------------------------------------------------------- /test/gateway_composer/destroy.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | 20 | const utils = require('../test_lib/utils'); 21 | const gatewayComposerUtils = require('./utils'); 22 | 23 | const { AccountProvider } = require('../test_lib/utils.js'); 24 | const web3 = require('../test_lib/web3.js'); 25 | 26 | contract('GatewayComposer::destroy', async (accounts) => { 27 | describe('Negative Tests', async () => { 28 | const accountProvider = new AccountProvider(accounts); 29 | 30 | it('Fails when GatewayComposer ValueToken balance is not zero.', async () => { 31 | const { 32 | valueToken, 33 | gatewayComposer, 34 | owner, 35 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 36 | await valueToken.setBalance(gatewayComposer.address, new BN(10)); 37 | await utils.expectRevert( 38 | gatewayComposer.destroy({ from: owner }), 39 | 'It should revert as ValueToken balance is not 0.', 40 | 'ValueToken balance should be 0.', 41 | ); 42 | }); 43 | 44 | it('Fails when owner is not msg.sender.', async () => { 45 | const { 46 | valueToken, 47 | gatewayComposer, 48 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 49 | await valueToken.setBalance(gatewayComposer.address, new BN(10)); 50 | await utils.expectRevert( 51 | gatewayComposer.destroy({ from: accountProvider.get() }), 52 | 'It should revert as only owner can call the function.', 53 | 'Only owner can call the function.', 54 | ); 55 | }); 56 | 57 | it('Fails when in progress stake requests are present.', async () => { 58 | const { 59 | valueToken, 60 | gatewayComposer, 61 | owner, 62 | brandedToken, 63 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 64 | 65 | const { 66 | stakeAmount, 67 | } = await gatewayComposerUtils.approveGatewayComposer( 68 | valueToken, 69 | gatewayComposer, 70 | owner, 71 | ); 72 | 73 | const mintAmount = await brandedToken.convertToBrandedTokens(stakeAmount); 74 | const gateway = accountProvider.get(); 75 | const beneficiary = accountProvider.get(); 76 | const gasPrice = 1; 77 | const gasLimit = 1; 78 | const nonce = 1; 79 | await gatewayComposer.requestStake( 80 | stakeAmount, 81 | mintAmount, 82 | gateway, 83 | beneficiary, 84 | gasPrice, 85 | gasLimit, 86 | nonce, 87 | { from: owner }, 88 | ); 89 | await utils.expectRevert( 90 | gatewayComposer.destroy({ from: owner }), 91 | 'It should revert as there are ongoing stake requests.', 92 | 'In progress stake requests are present.', 93 | ); 94 | }); 95 | }); 96 | 97 | describe('Storage', async () => { 98 | let accountProvider; 99 | 100 | beforeEach(async () => { 101 | accountProvider = new AccountProvider(accounts); 102 | }); 103 | 104 | it('Removes contract storage & code.', async () => { 105 | const { 106 | gatewayComposer, 107 | owner, 108 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 109 | 110 | await gatewayComposer.destroy({ from: owner }); 111 | 112 | const code = await web3.eth.getCode(gatewayComposer.address); 113 | assert.strictEqual( 114 | code, 115 | '0x', 116 | 'Bytecode must be 0x.', 117 | ); 118 | }); 119 | }); 120 | }); 121 | -------------------------------------------------------------------------------- /test/gateway_composer/revert_stake.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const { AccountProvider } = require('../test_lib/utils.js'); 20 | const web3 = require('../test_lib/web3.js'); 21 | 22 | const gatewayComposerUtils = require('./utils'); 23 | 24 | contract('GatewayComposer::revertStake', async (accounts) => { 25 | contract('Negative Tests', async () => { 26 | const accountProvider = new AccountProvider(accounts); 27 | 28 | it('Fails when owner is not the caller', async () => { 29 | const { 30 | gatewayComposer, 31 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 32 | 33 | const { 34 | gateway, 35 | } = await gatewayComposerUtils.setupGatewayPass( 36 | accountProvider, 37 | ); 38 | 39 | const penalty = 0; 40 | const messageHash = web3.utils.soliditySha3('hash'); 41 | 42 | await utils.expectRevert( 43 | gatewayComposer.revertStake( 44 | gateway.address, 45 | penalty, 46 | messageHash, 47 | { from: accountProvider.get() }, 48 | ), 49 | 'Should revert as msg.sender is not the owner.', 50 | 'Only owner can call the function.', 51 | ); 52 | }); 53 | 54 | it('Fails when gateway address is zero', async () => { 55 | const { 56 | gatewayComposer, 57 | owner, 58 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 59 | 60 | const gateway = utils.NULL_ADDRESS; 61 | const penalty = 0; 62 | const messageHash = web3.utils.soliditySha3('hash'); 63 | 64 | await utils.expectRevert( 65 | gatewayComposer.revertStake( 66 | gateway, 67 | penalty, 68 | messageHash, 69 | { from: owner }, 70 | ), 71 | 'Should revert as gateway address is zero.', 72 | 'Gateway address is zero.', 73 | ); 74 | }); 75 | 76 | it('Fails when gateway address is same as owner address', async () => { 77 | const { 78 | gatewayComposer, 79 | owner, 80 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 81 | 82 | const penalty = 0; 83 | const messageHash = web3.utils.soliditySha3('hash'); 84 | 85 | await utils.expectRevert( 86 | gatewayComposer.revertStake( 87 | owner, 88 | penalty, 89 | messageHash, 90 | { from: owner }, 91 | ), 92 | 'Should revert as gateway address and owner address are same.', 93 | 'Gateway address is same as owner address.', 94 | ); 95 | }); 96 | 97 | it('Fails if valueToken transferFrom returns false', async () => { 98 | const { 99 | gatewayComposer, 100 | owner, 101 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 102 | 103 | const { 104 | gateway, 105 | } = await gatewayComposerUtils.setupGatewayPass( 106 | accountProvider, 107 | ); 108 | 109 | const penalty = 1; 110 | const messageHash = web3.utils.soliditySha3('hash'); 111 | 112 | await utils.expectRevert( 113 | gatewayComposer.revertStake( 114 | gateway.address, 115 | penalty, 116 | messageHash, 117 | { from: owner }, 118 | ), 119 | 'Should revert as valueToken.transferFrom returned false.', 120 | ); 121 | }); 122 | }); 123 | 124 | contract('Positive Tests', async () => { 125 | const accountProvider = new AccountProvider(accounts); 126 | 127 | it('Returns true on successful execution', async () => { 128 | const { 129 | gatewayComposer, 130 | owner, 131 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 132 | 133 | const { 134 | gateway, 135 | } = await gatewayComposerUtils.setupGatewayPass( 136 | accountProvider, 137 | ); 138 | 139 | const penalty = 0; 140 | const messageHash = web3.utils.soliditySha3('hash'); 141 | 142 | assert.isOk( 143 | await gatewayComposer.revertStake.call( 144 | gateway.address, 145 | penalty, 146 | messageHash, 147 | { from: owner }, 148 | ), 149 | ); 150 | }); 151 | }); 152 | }); 153 | -------------------------------------------------------------------------------- /test/gateway_composer/revoke_stake_request.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const utils = require('../test_lib/utils'); 20 | const { AccountProvider } = require('../test_lib/utils.js'); 21 | const web3 = require('../test_lib/web3.js'); 22 | 23 | const gatewayComposerUtils = require('./utils'); 24 | 25 | contract('GatewayComposer::revokeStakeRequest', async (accounts) => { 26 | describe('Negative Tests', async () => { 27 | const accountProvider = new AccountProvider(accounts); 28 | 29 | it('Fails when owner is not the caller.', async () => { 30 | const { 31 | gatewayComposer, 32 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 33 | 34 | const stakeRequestHash = web3.utils.soliditySha3('hash'); 35 | await utils.expectRevert(gatewayComposer.revokeStakeRequest( 36 | stakeRequestHash, 37 | { from: accountProvider.get() }, 38 | ), 39 | 'Should revert as msg.sender is not the owner.', 40 | 'Only owner can call the function.'); 41 | }); 42 | 43 | it('Fails when stake request is not found.', async () => { 44 | const { 45 | gatewayComposer, 46 | owner, 47 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 48 | 49 | const invalidStakeRequestHash = web3.utils.soliditySha3('invalid'); 50 | await utils.expectRevert(gatewayComposer.revokeStakeRequest( 51 | invalidStakeRequestHash, 52 | { from: owner }, 53 | ), 54 | 'Should revert as stake request not found.', 55 | 'Stake request not found.'); 56 | }); 57 | 58 | it('Fails when BrandedToken.revokeStakeRequest returned false.', async () => { 59 | const { 60 | gatewayComposer, 61 | brandedToken, 62 | valueToken, 63 | owner, 64 | } = await gatewayComposerUtils.setupGatewayComposer( 65 | accountProvider, 66 | false, 67 | ); 68 | 69 | const { 70 | stakeAmount, 71 | } = await gatewayComposerUtils.approveGatewayComposer( 72 | valueToken, 73 | gatewayComposer, 74 | owner, 75 | ); 76 | 77 | const mintAmount = await brandedToken.convertToBrandedTokens(stakeAmount); 78 | const gateway = accountProvider.get(); 79 | const beneficiary = accountProvider.get(); 80 | const gasPrice = 1; 81 | const gasLimit = 1; 82 | const nonce = 1; 83 | const stakeRequestHash = await gatewayComposer.requestStake.call( 84 | stakeAmount, 85 | mintAmount, 86 | gateway, 87 | beneficiary, 88 | gasPrice, 89 | gasLimit, 90 | nonce, 91 | { from: owner }, 92 | ); 93 | await gatewayComposer.requestStake( 94 | stakeAmount, 95 | mintAmount, 96 | gateway, 97 | beneficiary, 98 | gasPrice, 99 | gasLimit, 100 | nonce, 101 | { from: owner }, 102 | ); 103 | 104 | await utils.expectRevert(gatewayComposer.revokeStakeRequest( 105 | stakeRequestHash, 106 | { from: owner }, 107 | ), 108 | 'Should revert as BrandedToken revokeStakeRequest returned false.', 109 | 'BrandedToken revokeStakeRequest returned false.'); 110 | }); 111 | }); 112 | 113 | describe('Positive Tests', async () => { 114 | const accountProvider = new AccountProvider(accounts); 115 | 116 | it('Returns true on successful execution.', async () => { 117 | const { 118 | gatewayComposer, 119 | brandedToken, 120 | valueToken, 121 | owner, 122 | ownerValueTokenBalance, 123 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 124 | 125 | const { 126 | stakeAmount, 127 | } = await gatewayComposerUtils.approveGatewayComposer( 128 | valueToken, 129 | gatewayComposer, 130 | owner, 131 | ); 132 | 133 | const mintAmount = await brandedToken.convertToBrandedTokens(stakeAmount); 134 | const gateway = accountProvider.get(); 135 | const beneficiary = accountProvider.get(); 136 | const gasPrice = 1; 137 | const gasLimit = 1; 138 | const nonce = 1; 139 | const stakeRequestHash = await gatewayComposer.requestStake.call( 140 | stakeAmount, 141 | mintAmount, 142 | gateway, 143 | beneficiary, 144 | gasPrice, 145 | gasLimit, 146 | nonce, 147 | { from: owner }, 148 | ); 149 | await gatewayComposer.requestStake( 150 | stakeAmount, 151 | mintAmount, 152 | gateway, 153 | beneficiary, 154 | gasPrice, 155 | gasLimit, 156 | nonce, 157 | { from: owner }, 158 | ); 159 | 160 | const executionStatus = await gatewayComposer.revokeStakeRequest.call( 161 | stakeRequestHash, 162 | { from: owner }, 163 | ); 164 | assert.strictEqual(executionStatus, true); 165 | 166 | await gatewayComposer.revokeStakeRequest( 167 | stakeRequestHash, 168 | { from: owner }, 169 | ); 170 | 171 | // stakeRequestHash information is deleted 172 | const stakeRequest = await gatewayComposer.stakeRequests.call( 173 | stakeRequestHash, 174 | ); 175 | assert.strictEqual( 176 | (stakeRequest.stakeVT).cmp(new BN(0)), 177 | 0, 178 | ); 179 | 180 | // Asserts owner balance. 181 | assert.strictEqual( 182 | (await valueToken.balanceOf.call(owner)).cmp(ownerValueTokenBalance), 183 | 0, 184 | ); 185 | 186 | // Sanity check in brandedToken. 187 | // stakeRequestHash information is deleted in BrandedToken. 188 | const btStakeRequest = await brandedToken.stakeRequests.call( 189 | stakeRequestHash, 190 | ); 191 | assert.strictEqual( 192 | btStakeRequest.staker, 193 | utils.NULL_ADDRESS, 194 | ); 195 | }); 196 | }); 197 | }); 198 | -------------------------------------------------------------------------------- /test/gateway_composer/transfer_token.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | const utils = require('../test_lib/utils'); 20 | const { AccountProvider } = require('../test_lib/utils.js'); 21 | 22 | const gatewayComposerUtils = require('./utils'); 23 | 24 | contract('GatewayComposer::transferToken', async (accounts) => { 25 | describe('Negative Tests', async () => { 26 | const accountProvider = new AccountProvider(accounts); 27 | 28 | it('Fails when owner is not the caller.', async () => { 29 | const { 30 | gatewayComposer, 31 | valueToken, 32 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 33 | 34 | const to = accountProvider.get(); 35 | const amount = new BN(10); 36 | await utils.expectRevert(gatewayComposer.transferToken( 37 | valueToken.address, 38 | to, 39 | amount, 40 | { from: accountProvider.get() }, 41 | ), 42 | 'Should revert as msg.sender is not the owner.', 43 | 'Only owner can call the function.'); 44 | }); 45 | 46 | it('Fails when EIP20 token address is invalid.', async () => { 47 | const { 48 | gatewayComposer, 49 | owner, 50 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 51 | 52 | const to = accountProvider.get(); 53 | const amount = new BN(10); 54 | await utils.expectRevert(gatewayComposer.transferToken( 55 | utils.NULL_ADDRESS, 56 | to, 57 | amount, 58 | { from: owner }, 59 | ), 60 | 'Should revert as token address is null.', 61 | 'EIP20 token address is zero.'); 62 | }); 63 | 64 | it('Fails when ValueToken transfer returned false.', async () => { 65 | const { 66 | gatewayComposer, 67 | valueToken, 68 | owner, 69 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 70 | 71 | // Set GatewayComposer address balance to 0. 72 | await valueToken.setBalance(gatewayComposer.address, new BN(0)); 73 | 74 | const to = accountProvider.get(); 75 | const amount = new BN(10); 76 | await utils.expectRevert(gatewayComposer.transferToken( 77 | valueToken.address, 78 | to, 79 | amount, 80 | { from: owner }, 81 | ), 82 | "Should revert as owner doesn't have sufficient balance."); 83 | }); 84 | }); 85 | 86 | describe('Positive Tests', async () => { 87 | const accountProvider = new AccountProvider(accounts); 88 | 89 | it('Returns true on successful execution.', async () => { 90 | const { 91 | gatewayComposer, 92 | valueToken, 93 | owner, 94 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 95 | 96 | const amount = new BN(10); 97 | // Set GatewayComposer address balance. 98 | await valueToken.setBalance(gatewayComposer.address, amount); 99 | const to = accountProvider.get(); 100 | const executionStatus = await gatewayComposer.transferToken.call( 101 | valueToken.address, 102 | to, 103 | amount, 104 | { from: owner }, 105 | ); 106 | assert.strictEqual(executionStatus, true); 107 | }); 108 | 109 | it('Validates destination address balance after calling transferToken.', async () => { 110 | const { 111 | gatewayComposer, 112 | valueToken, 113 | owner, 114 | } = await gatewayComposerUtils.setupGatewayComposer(accountProvider); 115 | 116 | const amount = new BN(10); 117 | // Set GatewayComposer address balance. 118 | await valueToken.setBalance(gatewayComposer.address, amount); 119 | const to = accountProvider.get(); 120 | const toBalanceBefore = await valueToken.balanceOf.call(to); 121 | await gatewayComposer.transferToken( 122 | valueToken.address, 123 | to, 124 | amount, 125 | { from: owner }, 126 | ); 127 | 128 | const toBalanceAfter = await valueToken.balanceOf.call(to); 129 | assert.strictEqual( 130 | toBalanceAfter.cmp(toBalanceBefore.add(amount)), 131 | 0, 132 | ); 133 | }); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /test/gateway_composer/utils.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OST.com Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | 20 | const config = require('../test_lib/config'); 21 | 22 | const BrandedToken = artifacts.require('BrandedToken'); 23 | const MockBrandedTokenFail = artifacts.require('MockBrandedTokenFail'); 24 | const GatewayComposer = artifacts.require('GatewayComposer'); 25 | const EIP20TokenMock = artifacts.require('EIP20TokenMock'); 26 | const MockGatewayPass = artifacts.require('MockGatewayPass'); 27 | const MockGatewayFail = artifacts.require('MockGatewayFail'); 28 | const MockOrganization = artifacts.require('OrganizationMockPass'); 29 | 30 | const symbol = 'Test'; 31 | const name = 'Test'; 32 | const { decimals } = config; 33 | const conversionRate = 1; 34 | const conversionRateDecimals = 0; 35 | 36 | module.exports.setupGatewayComposer = async (accountProvider, useBTPass = true) => { 37 | const organizationInstance = await MockOrganization.new(); 38 | const organization = organizationInstance.address; 39 | const deployer = accountProvider.get(); 40 | const owner = accountProvider.get(); 41 | const ownerValueTokenBalance = new BN(1000); 42 | 43 | const valueToken = await EIP20TokenMock.new( 44 | symbol, 45 | name, 46 | decimals, 47 | { from: deployer }, 48 | ); 49 | 50 | await valueToken.setBalance(owner, ownerValueTokenBalance); 51 | 52 | assert.strictEqual( 53 | (await valueToken.balanceOf.call(owner)).cmp(ownerValueTokenBalance), 54 | 0, 55 | ); 56 | 57 | let brandedToken; 58 | if (useBTPass === true) { 59 | brandedToken = await this.setupBrandedTokenPass(valueToken, organization); 60 | } else { 61 | brandedToken = await this.setupBrandedTokenFail(valueToken, organization); 62 | } 63 | 64 | const gatewayComposer = await GatewayComposer.new( 65 | owner, 66 | valueToken.address, 67 | brandedToken.address, 68 | ); 69 | 70 | return { 71 | valueToken, 72 | brandedToken, 73 | gatewayComposer, 74 | owner, 75 | organization, 76 | ownerValueTokenBalance, 77 | }; 78 | }; 79 | 80 | module.exports.setupBrandedTokenPass = async (valueToken, organization) => { 81 | const brandedToken = await BrandedToken.new( 82 | valueToken.address, 83 | symbol, 84 | name, 85 | decimals, 86 | conversionRate, 87 | conversionRateDecimals, 88 | organization, 89 | ); 90 | 91 | return brandedToken; 92 | }; 93 | 94 | module.exports.setupBrandedTokenFail = async (valueToken, organization) => { 95 | const brandedToken = await MockBrandedTokenFail.new( 96 | valueToken.address, 97 | symbol, 98 | name, 99 | decimals, 100 | conversionRate, 101 | conversionRateDecimals, 102 | organization, 103 | ); 104 | 105 | return brandedToken; 106 | }; 107 | 108 | module.exports.approveGatewayComposer = async (valueToken, gatewayComposer, owner) => { 109 | const stakeAmount = 1; 110 | 111 | await valueToken.approve( 112 | gatewayComposer.address, 113 | stakeAmount, 114 | { from: owner }, 115 | ); 116 | 117 | return { 118 | stakeAmount, 119 | }; 120 | }; 121 | 122 | module.exports.setupGatewayPass = async (accountProvider) => { 123 | const mockGatewayPass = await MockGatewayPass.new(); 124 | 125 | return { 126 | facilitator: accountProvider.get(), 127 | gateway: mockGatewayPass, 128 | }; 129 | }; 130 | 131 | module.exports.setupGatewayFail = async (accountProvider) => { 132 | const mockGatewayFail = await MockGatewayFail.new(); 133 | 134 | return { 135 | facilitator: accountProvider.get(), 136 | gateway: mockGatewayFail, 137 | }; 138 | }; 139 | -------------------------------------------------------------------------------- /test/test_lib/RevertProxy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // Copyright 2018 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | import "truffle/Assert.sol"; 18 | import "truffle/DeployedAddresses.sol"; 19 | 20 | /** 21 | * @title A proxy contract to catch and test for reverts in other contracts. 22 | * 23 | * @notice Use this contract as a proxy between the test contract and the 24 | * contract under test. It will catch reverts and return false if it 25 | * caught one. 26 | * 27 | * @dev An important caveat here is to recognize the contract caller, 28 | * msg.sender. If you add a proxy in between, then msg.sender will be the 29 | * proxy, which could break authorization and permissioning algorithms. If 30 | * your authorization system allows you to change the owner, you can get 31 | * around this constraint by setting the proxy to be the contract owner. 32 | * It’s also important to know that this only tests throw's at this 33 | * particular level. 34 | * It would be prudent to also ensure there isn’t anything faulty in the 35 | * proxy by creating a second test as a control. This test should be 36 | * called with the appropriate gas and use the proxy to test a function 37 | * where _no_ throw occurs, just to make sure the proxy is setup and 38 | * working as intended. 39 | * Because a throw essentially uses up all gas, one must make doubly sure 40 | * they catch the throw and not a legitimate out-of-gas (OOG) error. As 41 | * well, take care to manage sending Ether through the proxy (for tests 42 | * that require it) as that can be difficult as well. 43 | * 44 | * See also test/core/TestAuxiliaryStake.sol 45 | * 46 | * Usage: 47 | * contract TestThrower { 48 | * function testThrow() { 49 | * Thrower thrower = new Thrower(); 50 | * // Set Thrower as the contract to forward requests to the target. 51 | * RevertProxy revertProxy = new RevertProxy(address(thrower)); 52 | * 53 | * // Prime the proxy. 54 | * Thrower(address(revertProxy)).doThrow(); 55 | * // Execute the call that is supposed to revert. 56 | * // r will be false if it reverted. r will be true if it didn't. 57 | * // Make sure you send enough gas for your contract method. 58 | * bool r = revertProxy.execute.gas(200000)(); 59 | * 60 | * Assert.isFalse(r, “Should be false, as it should revert"); 61 | * } 62 | * } 63 | * 64 | * Inspired by: 65 | * https://truffleframework.com/tutorials/testing-for-throws-in-solidity-tests. 66 | */ 67 | contract RevertProxy { 68 | 69 | /* Public Variables */ 70 | 71 | /** target is the address of the contract under test. */ 72 | address public target; 73 | 74 | /** data stores the call data that will be sent to the method under test. */ 75 | bytes public data; 76 | 77 | /* Constructor */ 78 | 79 | /** 80 | * @param _target The address where the executed calls will be sent to. 81 | */ 82 | constructor (address _target) public { 83 | target = _target; 84 | } 85 | 86 | /* Public Functions */ 87 | 88 | /** 89 | * @notice Updates the target of the proxy so that all subsequent execute 90 | * calls will be made to the new target. 91 | * 92 | * @param _newTarget The address of the contract where to send all execute 93 | * calls to. 94 | */ 95 | function updateTarget(address _newTarget) public { 96 | target = _newTarget; 97 | } 98 | 99 | /** 100 | * @notice The fallback function stores the call data so that a call to the 101 | * execute function will use the correct call data. 102 | */ 103 | function() external payable { 104 | data = msg.data; 105 | } 106 | 107 | /** 108 | * @notice This will make the call to the target with the call data primed 109 | * in the fallback function. 110 | * 111 | * @return `true` if the call was successful and did not revert, `false` if 112 | * it reverted. 113 | */ 114 | function execute() external returns (bool, bytes memory) { 115 | // solium-disable-next-line security/no-low-level-calls 116 | return target.call(data); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /test/test_lib/config.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // ---------------------------------------------------------------------------- 16 | // 17 | // http://www.simpletoken.org/ 18 | // 19 | // ---------------------------------------------------------------------------- 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable @typescript-eslint/no-var-requires */ 24 | const { env } = require('process'); 25 | 26 | /** Test wide configuration for various tests. */ 27 | const config = { 28 | /** Defaults to 18. Can be overriden with the environment variable OPENST_DECIMALS. */ 29 | get decimals() { 30 | let decimals = 18; 31 | 32 | if (env.OPENST_DECIMALS) { 33 | decimals = Number.parseInt(env.OPENST_DECIMALS, 10); 34 | } 35 | 36 | return decimals; 37 | }, 38 | }; 39 | 40 | module.exports = config; 41 | -------------------------------------------------------------------------------- /test/test_lib/event_decoder.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const web3 = require('../test_lib/web3.js'); 19 | 20 | class Event { 21 | static decodeTransactionResponse(transactionResponse) { 22 | const events = []; 23 | 24 | assert.isOk(Object.prototype.hasOwnProperty.call( 25 | transactionResponse, 'logs', 26 | )); 27 | 28 | const { logs } = transactionResponse; 29 | 30 | for (let i = 0; i < logs.length; i += 1) { 31 | events.push({ 32 | name: logs[i].event, 33 | args: logs[i].args, 34 | }); 35 | } 36 | 37 | return events; 38 | } 39 | 40 | static assertEqual(actual, expected) { 41 | assert.strictEqual(actual.name, expected.name); 42 | Object.keys(expected.args).forEach((key) => { 43 | if (key !== '0' && key !== '1' && key !== '__length__') { 44 | assert.isOk(Object.hasOwnProperty.call(actual.args, key)); 45 | if (web3.utils.isBN(expected.args[key])) { 46 | assert.isOk(web3.utils.isBN(actual.args[key])); 47 | assert.isOk(expected.args[key].eq(actual.args[key])); 48 | } else { 49 | assert.strictEqual(actual.args[key], expected.args[key]); 50 | } 51 | } 52 | }); 53 | 54 | Object.keys(actual.args).forEach((key) => { 55 | if (Number.isNaN(Number.parseInt(key, 10)) && key !== '__length__') { 56 | assert.isOk(Object.hasOwnProperty.call(expected.args, key)); 57 | } 58 | }); 59 | } 60 | 61 | static assertEqualMulti(actualList, expectedList) { 62 | assert.strictEqual( 63 | actualList.length, 64 | expectedList.length, 65 | 'Length of actual event list and expected ones should be equal.', 66 | ); 67 | 68 | for (let i = 0; i < actualList.lengh; i += 1) { 69 | const actual = actualList[i]; 70 | const expected = expectedList[i]; 71 | this.assertEqual(actual, expected); 72 | } 73 | } 74 | } 75 | 76 | module.exports = { 77 | Event, 78 | }; 79 | -------------------------------------------------------------------------------- /test/test_lib/utils.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OST.com Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const BN = require('bn.js'); 19 | 20 | const assert = require('assert'); 21 | const web3 = require('web3'); 22 | 23 | const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; 24 | const NULL_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000'; 25 | const MAX_UINT256 = new BN(2).pow(new BN(256)).sub(new BN(1)); 26 | 27 | module.exports.NULL_ADDRESS = NULL_ADDRESS; 28 | module.exports.NULL_BYTES32 = NULL_BYTES32; 29 | module.exports.MAX_UINT256 = MAX_UINT256; 30 | 31 | module.exports.isNullAddress = address => address === NULL_ADDRESS; 32 | 33 | /** 34 | * Asserts that a call or transaction reverts. 35 | * 36 | * @param {promise} promise The call or transaction. 37 | * @param {string} expectedMessage Optional. If given, the revert message will 38 | * be checked to contain this string. 39 | * 40 | * @throws Will fail an assertion if the call or transaction is not reverted. 41 | */ 42 | module.exports.expectRevert = async ( 43 | promise, displayMessage, expectedRevertMessage, 44 | ) => { 45 | try { 46 | await promise; 47 | } catch (error) { 48 | assert( 49 | error.message.search('revert') > -1, 50 | `The contract should revert. Instead: ${error.message}`, 51 | ); 52 | 53 | if (expectedRevertMessage !== undefined) { 54 | if (error.reason !== undefined) { 55 | assert( 56 | expectedRevertMessage === error.reason, 57 | `\nThe contract should revert with:\n\t"${expectedRevertMessage}" ` 58 | + `\ninstead received:\n\t"${error.reason}"\n`, 59 | ); 60 | } else { 61 | assert( 62 | error.message.search(expectedRevertMessage) > -1, 63 | `\nThe contract should revert with:\n\t"${expectedRevertMessage}" ` 64 | + `\ninstead received:\n\t"${error.message}"\n`, 65 | ); 66 | } 67 | } 68 | 69 | return; 70 | } 71 | 72 | assert(false, displayMessage); 73 | }; 74 | 75 | module.exports.advanceBlock = async () => { 76 | await web3.currentProvider.send({ 77 | jsonrpc: '2.0', 78 | method: 'evm_mine', 79 | id: new Date().getTime(), 80 | }, (err) => { 81 | assert.strictEqual(err, null); 82 | }); 83 | }; 84 | 85 | /** Receives accounts list and gives away each time one. */ 86 | module.exports.AccountProvider = class AccountProvider { 87 | constructor(accounts) { 88 | this.accounts = accounts; 89 | this.index = 0; 90 | } 91 | 92 | get() { 93 | assert(this.index < this.accounts.length); 94 | const account = this.accounts[this.index]; 95 | this.index += 1; 96 | return account; 97 | } 98 | }; 99 | -------------------------------------------------------------------------------- /test/test_lib/web3.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const Web3 = require('web3'); 19 | 20 | const web3 = new Web3( 21 | new Web3.providers.WebsocketProvider('ws://localhost:8545'), 22 | ); 23 | 24 | module.exports = web3; 25 | -------------------------------------------------------------------------------- /test/utility_branded_token/constructor.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const config = require('../test_lib/config'); 19 | const utils = require('../test_lib/utils'); 20 | 21 | const UtilityBrandedToken = artifacts.require('UtilityBrandedToken'); 22 | const EIP20TokenMock = artifacts.require('EIP20TokenMock'); 23 | 24 | contract('UtilityBrandedToken::constructor', async (accounts) => { 25 | let brandedToken; 26 | let organization; 27 | let accountProvider; 28 | 29 | const SYMBOL = 'MOCK'; 30 | const NAME = 'Mock Token'; 31 | const { decimals: DECIMALS } = config; 32 | 33 | beforeEach(async () => { 34 | accountProvider = new utils.AccountProvider(accounts); 35 | organization = accountProvider.get(); 36 | brandedToken = await EIP20TokenMock.new( 37 | SYMBOL, 38 | NAME, 39 | DECIMALS, 40 | { from: organization }, 41 | ); 42 | }); 43 | 44 | describe('Negative Tests', async () => { 45 | it('Reverts if null address is passed as organization', async () => { 46 | await utils.expectRevert(UtilityBrandedToken.new( 47 | brandedToken.address, 48 | SYMBOL, 49 | NAME, 50 | DECIMALS, 51 | utils.NULL_ADDRESS, 52 | { from: organization }, 53 | ), 54 | 'Organization contract address should not be zero', 55 | 'Organization contract address must not be zero.'); 56 | }); 57 | }); 58 | 59 | describe('Storage', async () => { 60 | it('Successfully sets state variables', async () => { 61 | const utilityBrandedToken = await UtilityBrandedToken.new( 62 | brandedToken.address, 63 | SYMBOL, 64 | NAME, 65 | DECIMALS, 66 | organization, 67 | { from: organization }, 68 | ); 69 | 70 | assert.strictEqual( 71 | await utilityBrandedToken.token.call(), 72 | brandedToken.address, 73 | 'Branded token address is incorrect', 74 | ); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /test/utility_branded_token/decrease_supply.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const UtilityBrandedTokenUtils = require('./utils'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | const web3 = require('../test_lib/web3'); 22 | 23 | contract('UtilityBrandedToken::decreaseSupply', async (accounts) => { 24 | let testUtilityBrandedToken; 25 | let internalActors; 26 | let tokenHolder1; 27 | let tokenHolder2; 28 | let accountProvider; 29 | 30 | const amount = 10; 31 | const tokenHolder1Balance = 100; 32 | const decreasedAmount = 6; 33 | 34 | beforeEach(async () => { 35 | accountProvider = new utils.AccountProvider(accounts); 36 | tokenHolder1 = accountProvider.get(); 37 | tokenHolder2 = accountProvider.get(); 38 | 39 | internalActors = []; 40 | internalActors.push(tokenHolder1); 41 | internalActors.push(tokenHolder2); 42 | 43 | ({ 44 | testUtilityBrandedToken, 45 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 46 | accountProvider, internalActors, 47 | )); 48 | 49 | await testUtilityBrandedToken.setBalance(tokenHolder1, tokenHolder1Balance); 50 | }); 51 | 52 | describe('Storage', async () => { 53 | it('Correctly decreases the supply of tokens', async () => { 54 | const coGateway = tokenHolder2; 55 | await testUtilityBrandedToken.mockSetCoGateway(coGateway); 56 | await testUtilityBrandedToken.increaseSupply( 57 | coGateway, 58 | amount, 59 | { from: tokenHolder2 }, 60 | ); 61 | 62 | // Before decrease supply. 63 | assert.strictEqual( 64 | (await testUtilityBrandedToken.balanceOf(coGateway)).cmp( 65 | web3.utils.toBN(amount), 66 | ), 67 | 0, 68 | `Balance of coGateway should be ${amount}`, 69 | ); 70 | assert.strictEqual( 71 | (await testUtilityBrandedToken.totalSupply()).cmp( 72 | web3.utils.toBN(amount), 73 | ), 74 | 0, 75 | `Total supply should be ${amount}`, 76 | ); 77 | 78 | await testUtilityBrandedToken.decreaseSupply(decreasedAmount, { from: coGateway }); 79 | 80 | // After decrease supply. 81 | assert.strictEqual( 82 | (await testUtilityBrandedToken.balanceOf(coGateway)).cmp( 83 | web3.utils.toBN(amount - decreasedAmount), 84 | ), 85 | 0, 86 | `Balance of coGateway should be ${amount - decreasedAmount}`, 87 | ); 88 | assert.strictEqual( 89 | (await testUtilityBrandedToken.totalSupply()).cmp( 90 | web3.utils.toBN(amount - decreasedAmount), 91 | ), 92 | 0, 93 | `Total supply should be ${amount - decreasedAmount}`, 94 | ); 95 | }); 96 | }); 97 | 98 | describe('Events', async () => { 99 | it('Emits a Transfer event', async () => { 100 | const coGateway = tokenHolder2; 101 | await testUtilityBrandedToken.mockSetCoGateway(coGateway); 102 | await testUtilityBrandedToken.increaseSupply( 103 | coGateway, 104 | amount, 105 | { from: tokenHolder2 }, 106 | ); 107 | 108 | const transactionResponse = await testUtilityBrandedToken.decreaseSupply( 109 | decreasedAmount, 110 | { from: coGateway }, 111 | ); 112 | 113 | const events = Event.decodeTransactionResponse(transactionResponse); 114 | 115 | assert.strictEqual( 116 | events.length, 117 | 1, 118 | ); 119 | 120 | Event.assertEqual(events[0], { 121 | name: 'Transfer', 122 | args: { 123 | _from: coGateway, 124 | _to: utils.NULL_ADDRESS, 125 | _value: new web3.utils.BN(decreasedAmount), 126 | }, 127 | }); 128 | }); 129 | }); 130 | }); 131 | -------------------------------------------------------------------------------- /test/utility_branded_token/exists.js: -------------------------------------------------------------------------------- 1 | // Copyright 2019 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const UtilityBrandedTokenUtils = require('./utils'); 20 | 21 | contract('UtilityBrandedToken::exists', async (accounts) => { 22 | let accountProvider; 23 | 24 | beforeEach(async () => { 25 | accountProvider = new utils.AccountProvider(accounts); 26 | }); 27 | 28 | describe('Returns', async () => { 29 | it('Returns false if account is not an internal actor', async () => { 30 | const actor = await accountProvider.get(); 31 | const { 32 | testUtilityBrandedToken, 33 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 34 | accountProvider, 35 | [actor], 36 | ); 37 | 38 | const nonInternalAccount = await accountProvider.get(); 39 | 40 | assert.strictEqual( 41 | await testUtilityBrandedToken.exists.call(nonInternalAccount), 42 | false, 43 | 'It should return false for non internal actor', 44 | ); 45 | }); 46 | 47 | it('Returns true if account is an internal actor', async () => { 48 | const actor = await accountProvider.get(); 49 | const { 50 | testUtilityBrandedToken, 51 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 52 | accountProvider, 53 | [actor], 54 | ); 55 | 56 | assert.strictEqual( 57 | await testUtilityBrandedToken.exists.call(actor), 58 | true, 59 | 'It should returns for an internal actor', 60 | ); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/utility_branded_token/increase_supply.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const UtilityBrandedTokenUtils = require('./utils'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | const web3 = require('../test_lib/web3'); 22 | 23 | contract('UtilityBrandedToken::increaseSupply', async (accounts) => { 24 | let testUtilityBrandedToken; 25 | let internalActors; 26 | let tokenHolder1; 27 | let tokenHolder2; 28 | let tokenHolder3; 29 | let accountProvider; 30 | let coGateway; 31 | 32 | const amount = 10; 33 | const tokenHolder1Balance = 100; 34 | 35 | beforeEach(async () => { 36 | accountProvider = new utils.AccountProvider(accounts); 37 | tokenHolder1 = accountProvider.get(); 38 | tokenHolder2 = accountProvider.get(); 39 | tokenHolder3 = accountProvider.get(); 40 | coGateway = accountProvider.get(); 41 | 42 | internalActors = []; 43 | internalActors.push(tokenHolder1); 44 | internalActors.push(tokenHolder3); 45 | 46 | ({ 47 | testUtilityBrandedToken, 48 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 49 | accountProvider, internalActors, 50 | )); 51 | 52 | await testUtilityBrandedToken.setBalance(tokenHolder1, tokenHolder1Balance); 53 | await testUtilityBrandedToken.mockSetCoGateway(coGateway); 54 | }); 55 | 56 | describe('Negative Tests', async () => { 57 | it('Reverts if beneficiary address is not registered internal actor', async () => { 58 | await utils.expectRevert( 59 | testUtilityBrandedToken.increaseSupply( 60 | tokenHolder2, 61 | amount, 62 | { from: coGateway }, 63 | ), 64 | 'Beneficiary should be registered internal actor', 65 | 'Beneficiary is not an internal actor.', 66 | ); 67 | }); 68 | }); 69 | 70 | describe('Storage', async () => { 71 | it('Correctly increases the supply of tokens', async () => { 72 | // Before increase in supply 73 | assert.strictEqual( 74 | (await testUtilityBrandedToken.balanceOf(tokenHolder3)).cmp( 75 | web3.utils.toBN(0), 76 | ), 77 | 0, 78 | 'Balance of tokeholder3 should be zero', 79 | ); 80 | assert.strictEqual( 81 | (await testUtilityBrandedToken.totalSupply()).cmp( 82 | web3.utils.toBN(0), 83 | ), 84 | 0, 85 | 'Total supply should be zero', 86 | ); 87 | 88 | await testUtilityBrandedToken.increaseSupply( 89 | tokenHolder3, 90 | amount, 91 | { from: coGateway }, 92 | ); 93 | 94 | // After increase supply. 95 | assert.strictEqual( 96 | (await testUtilityBrandedToken.totalSupply()).cmp( 97 | web3.utils.toBN(amount), 98 | ), 99 | 0, 100 | `Total supply should be ${amount}`, 101 | ); 102 | assert.strictEqual( 103 | (await testUtilityBrandedToken.balanceOf(tokenHolder3)).cmp( 104 | web3.utils.toBN(amount), 105 | ), 106 | 0, 107 | `Total supply should be ${amount}`, 108 | ); 109 | }); 110 | }); 111 | 112 | describe('Events', async () => { 113 | it('Emits a Transfer event', async () => { 114 | const transactionResponse = await testUtilityBrandedToken.increaseSupply( 115 | tokenHolder3, 116 | amount, 117 | { from: coGateway }, 118 | ); 119 | 120 | const events = Event.decodeTransactionResponse(transactionResponse); 121 | 122 | assert.strictEqual( 123 | events.length, 124 | 1, 125 | ); 126 | 127 | Event.assertEqual(events[0], { 128 | name: 'Transfer', 129 | args: { 130 | _from: utils.NULL_ADDRESS, 131 | _to: tokenHolder3, 132 | _value: new web3.utils.BN(amount), 133 | }, 134 | }); 135 | }); 136 | }); 137 | }); 138 | -------------------------------------------------------------------------------- /test/utility_branded_token/register_internal_actors.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const { Event } = require('../test_lib/event_decoder'); 20 | const UtilityBrandedTokenUtils = require('./utils'); 21 | 22 | contract('Internal::registerInternalActors', async (accounts) => { 23 | let organization; 24 | let accountProvider; 25 | let worker; 26 | let testUtilityBrandedToken; 27 | 28 | beforeEach(async () => { 29 | accountProvider = new utils.AccountProvider(accounts); 30 | 31 | ({ 32 | testUtilityBrandedToken, 33 | organization, 34 | worker, 35 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 36 | accountProvider, [], 37 | )); 38 | }); 39 | 40 | describe('Negative Tests', async () => { 41 | it('Reverts if non-worker address is adding internal actor', async () => { 42 | const internalActors = []; 43 | internalActors.push(accountProvider.get()); 44 | const nonWorker = accountProvider.get(); 45 | 46 | await utils.expectRevert(testUtilityBrandedToken.registerInternalActors( 47 | internalActors, 48 | { from: nonWorker }, 49 | ), 50 | 'Worker should be registered.', 51 | 'Only whitelisted workers are allowed to call this method.'); 52 | }); 53 | }); 54 | 55 | describe('Events', async () => { 56 | it('Emits InternalActorRegistered events for multiple internal actors registration', async () => { 57 | const internalActors = []; 58 | internalActors.push(accountProvider.get()); 59 | internalActors.push(accountProvider.get()); 60 | internalActors.push(accountProvider.get()); 61 | 62 | const transactionResponse = await testUtilityBrandedToken.registerInternalActors( 63 | internalActors, 64 | { from: worker }, 65 | ); 66 | 67 | const events = Event.decodeTransactionResponse( 68 | transactionResponse, 69 | ); 70 | 71 | Event.assertEqualMulti(events, [{ 72 | name: 'InternalActorRegistered', 73 | args: 74 | { 75 | _organization: organization, 76 | _actor: internalActors[0], 77 | }, 78 | }, 79 | { 80 | name: 'InternalActorRegistered', 81 | args: 82 | { 83 | _organization: organization, 84 | _actor: internalActors[1], 85 | }, 86 | }, 87 | { 88 | name: 'InternalActorRegistered', 89 | args: 90 | { 91 | _organization: organization, 92 | _actor: internalActors[2], 93 | }, 94 | }, 95 | ]); 96 | }); 97 | 98 | it('Doesn\'t register already registered internal actor', async () => { 99 | const internalActors = []; 100 | internalActors.push(accountProvider.get()); 101 | 102 | await testUtilityBrandedToken.registerInternalActors( 103 | internalActors, 104 | { from: worker }, 105 | ); 106 | 107 | const transactionResponse = await testUtilityBrandedToken.registerInternalActors( 108 | internalActors, 109 | { from: worker }, 110 | ); 111 | 112 | const events = Event.decodeTransactionResponse( 113 | transactionResponse, 114 | ); 115 | 116 | assert.strictEqual( 117 | events.length, 118 | 0, 119 | 'Should not emit InternalActorRegistered event', 120 | ); 121 | }); 122 | }); 123 | 124 | describe('Storage', async () => { 125 | it('Successfully registers internal actors', async () => { 126 | const internalActors = []; 127 | internalActors.push(accountProvider.get()); 128 | internalActors.push(accountProvider.get()); 129 | 130 | await testUtilityBrandedToken.registerInternalActors( 131 | internalActors, 132 | { from: worker }, 133 | ); 134 | 135 | assert.strictEqual( 136 | await testUtilityBrandedToken.isInternalActor.call(internalActors[0]), 137 | true, 138 | ); 139 | assert.strictEqual( 140 | await testUtilityBrandedToken.isInternalActor.call(internalActors[1]), 141 | true, 142 | ); 143 | }); 144 | }); 145 | }); 146 | -------------------------------------------------------------------------------- /test/utility_branded_token/set_cogateway.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const UtilityBrandedTokenUtils = require('./utils'); 20 | const { Event } = require('../test_lib/event_decoder.js'); 21 | 22 | const MockCoGateway = artifacts.require('MockCoGateway'); 23 | 24 | contract('UtilityBrandedToken::setCoGateway', async (accounts) => { 25 | let internalActor; 26 | let tokenHolder1; 27 | let tokenHolder3; 28 | let accountProvider; 29 | let mockCoGateway; 30 | let testUtilityBrandedToken; 31 | let testUtilityBrandedToken2; 32 | let organization; 33 | 34 | const tokenHolder1Balance = 100; 35 | 36 | beforeEach(async () => { 37 | accountProvider = new utils.AccountProvider(accounts); 38 | tokenHolder1 = accountProvider.get(); 39 | tokenHolder3 = accountProvider.get(); 40 | 41 | internalActor = []; 42 | internalActor.push(tokenHolder1); 43 | internalActor.push(tokenHolder3); 44 | 45 | ({ 46 | testUtilityBrandedToken, 47 | organization, 48 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 49 | accountProvider, internalActor, 50 | )); 51 | 52 | mockCoGateway = await MockCoGateway.new( 53 | testUtilityBrandedToken.address, 54 | ); 55 | 56 | await testUtilityBrandedToken.setBalance(tokenHolder1, tokenHolder1Balance); 57 | }); 58 | 59 | describe('Negative Tests', async () => { 60 | it('Reverts if non-owner address sets the coGateway', async () => { 61 | const nonOrganization = accountProvider.get(); 62 | await utils.expectRevert(testUtilityBrandedToken.setCoGateway( 63 | mockCoGateway.address, 64 | { from: nonOrganization }, 65 | ), 66 | 'Only organization or admin can call', 67 | 'Only the organization is allowed to call this method.'); 68 | }); 69 | 70 | it('Reverts if coGateway address is zero', async () => { 71 | await utils.expectRevert(testUtilityBrandedToken.setCoGateway( 72 | utils.NULL_ADDRESS, 73 | { from: organization }, 74 | ), 75 | 'Only organization or admin can call', 76 | 'CoGateway address should not be zero.'); 77 | }); 78 | 79 | it('Reverts if coGateway address is already set', async () => { 80 | await testUtilityBrandedToken.setCoGateway( 81 | mockCoGateway.address, 82 | { from: organization }, 83 | ); 84 | 85 | const mockCoGateway2 = await MockCoGateway.new( 86 | testUtilityBrandedToken.address, 87 | ); 88 | 89 | await utils.expectRevert(testUtilityBrandedToken.setCoGateway( 90 | mockCoGateway2.address, 91 | { from: organization }, 92 | ), 93 | 'CoGateway address cannot be set again.', 94 | 'CoGateway address is already set.'); 95 | }); 96 | 97 | it('Reverts if CoGateway is linked to other utility token', async () => { 98 | const utilityMock = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 99 | accountProvider, internalActor, 100 | ); 101 | 102 | testUtilityBrandedToken2 = utilityMock.testUtilityBrandedToken; 103 | 104 | const mockCoGateway2 = await MockCoGateway.new( 105 | testUtilityBrandedToken2.address, 106 | ); 107 | 108 | await utils.expectRevert(testUtilityBrandedToken.setCoGateway( 109 | mockCoGateway2.address, 110 | { from: organization }, 111 | ), 112 | 'CoGateway is linked to other utility token', 113 | 'CoGateway should be linked with this utility token.'); 114 | }); 115 | }); 116 | 117 | describe('Storage', async () => { 118 | it('Successfully sets the coGateway address', async () => { 119 | await testUtilityBrandedToken.setCoGateway( 120 | mockCoGateway.address, 121 | { from: organization }, 122 | ); 123 | 124 | assert.strictEqual( 125 | await testUtilityBrandedToken.coGateway.call(), 126 | mockCoGateway.address, 127 | 'CoGateway address is incorrect', 128 | ); 129 | }); 130 | 131 | it('Checks that coGateway is set as an internal actor.', async () => { 132 | await testUtilityBrandedToken.setCoGateway( 133 | mockCoGateway.address, 134 | { from: organization }, 135 | ); 136 | 137 | assert.isOk( 138 | await testUtilityBrandedToken.isInternalActor.call(mockCoGateway.address), 139 | ); 140 | }); 141 | }); 142 | 143 | describe('Events', async () => { 144 | it('Emits a CoGatewaySet event', async () => { 145 | const transactionResponse = await testUtilityBrandedToken.setCoGateway( 146 | mockCoGateway.address, 147 | { from: organization }, 148 | ); 149 | 150 | const events = Event.decodeTransactionResponse(transactionResponse); 151 | 152 | assert.strictEqual( 153 | events.length, 154 | 1, 155 | 'Only one event should be raised', 156 | ); 157 | 158 | Event.assertEqual(events[0], { 159 | name: 'CoGatewaySet', 160 | args: { 161 | _coGateway: mockCoGateway.address, 162 | }, 163 | }); 164 | }); 165 | }); 166 | }); 167 | -------------------------------------------------------------------------------- /test/utility_branded_token/transfer.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const UtilityBrandedTokenUtils = require('./utils'); 20 | const web3 = require('../test_lib/web3'); 21 | 22 | contract('UtilityBrandedToken::transfer', async (accounts) => { 23 | let testUtilityBrandedToken; 24 | let internalActors; 25 | let tokenHolder1; 26 | let tokenHolder2; 27 | let worker; 28 | let accountProvider; 29 | 30 | const amount = 10; 31 | const tokenHolder1Balance = 100; 32 | 33 | beforeEach(async () => { 34 | accountProvider = new utils.AccountProvider(accounts); 35 | tokenHolder1 = accountProvider.get(); 36 | tokenHolder2 = accountProvider.get(); 37 | 38 | internalActors = []; 39 | internalActors.push(tokenHolder1); 40 | 41 | ({ 42 | testUtilityBrandedToken, 43 | worker, 44 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 45 | accountProvider, internalActors, 46 | )); 47 | 48 | await testUtilityBrandedToken.setBalance(tokenHolder1, tokenHolder1Balance); 49 | }); 50 | 51 | describe('Negative Tests', async () => { 52 | it('Reverts if to address is not registered internal actor', async () => { 53 | await utils.expectRevert(testUtilityBrandedToken.transfer( 54 | tokenHolder2, 55 | amount, 56 | { from: tokenHolder1 }, 57 | ), 58 | 'To address should be registered internal actor', 59 | 'To address is not an internal actor.'); 60 | }); 61 | }); 62 | 63 | describe('Storage', async () => { 64 | it('Successfully transfers to internal actor', async () => { 65 | internalActors.push(tokenHolder2); 66 | 67 | await testUtilityBrandedToken.registerInternalActors( 68 | internalActors, 69 | { from: worker }, 70 | ); 71 | 72 | assert.strictEqual( 73 | (await testUtilityBrandedToken.balanceOf(tokenHolder2)).cmp( 74 | web3.utils.toBN(0), 75 | ), 76 | 0, 77 | 'Tokenholder2 balance should be zero', 78 | ); 79 | 80 | await testUtilityBrandedToken.transfer( 81 | tokenHolder2, 82 | amount, 83 | { from: tokenHolder1 }, 84 | ); 85 | 86 | assert.strictEqual( 87 | (await testUtilityBrandedToken.balanceOf(tokenHolder2)).cmp( 88 | web3.utils.toBN(amount), 89 | ), 90 | 0, 91 | `Balance of tokenholder2 should be ${amount}`, 92 | ); 93 | }); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/utility_branded_token/transfer_from.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OpenST Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const utils = require('../test_lib/utils'); 19 | const UtilityBrandedTokenUtils = require('./utils'); 20 | const web3 = require('../test_lib/web3'); 21 | 22 | contract('UtilityBrandedToken::transferFrom', async (accounts) => { 23 | let testUtilityBrandedToken; 24 | let internalActors; 25 | let tokenHolder1; 26 | let tokenHolder2; 27 | let tokenHolder3; 28 | let worker; 29 | let accountProvider; 30 | 31 | const approvalAmount = 50; 32 | const amount = 10; 33 | const tokenHolder1Balance = 100; 34 | 35 | beforeEach(async () => { 36 | accountProvider = new utils.AccountProvider(accounts); 37 | tokenHolder1 = accountProvider.get(); 38 | tokenHolder2 = accountProvider.get(); 39 | tokenHolder3 = accountProvider.get(); 40 | worker = accountProvider.get(); 41 | 42 | internalActors = []; 43 | internalActors.push(tokenHolder1); 44 | internalActors.push(tokenHolder3); 45 | 46 | ({ 47 | testUtilityBrandedToken, 48 | worker, 49 | } = await UtilityBrandedTokenUtils.setupUtilityBrandedToken( 50 | accountProvider, internalActors, 51 | )); 52 | 53 | await testUtilityBrandedToken.registerInternalActors( 54 | internalActors, 55 | { from: worker }, 56 | ); 57 | 58 | await testUtilityBrandedToken.setBalance(tokenHolder1, tokenHolder1Balance); 59 | 60 | await testUtilityBrandedToken.approve( 61 | tokenHolder3, 62 | approvalAmount, 63 | { from: tokenHolder1 }, 64 | ); 65 | }); 66 | 67 | describe('Negative Tests', async () => { 68 | it('Reverts if to address is not registered internal actor', async () => { 69 | await utils.expectRevert(testUtilityBrandedToken.transferFrom( 70 | tokenHolder1, 71 | tokenHolder2, 72 | amount, 73 | { from: tokenHolder3 }, 74 | ), 75 | 'To address should be registered internal actor', 76 | 'To address is not an internal actor.'); 77 | }); 78 | }); 79 | 80 | describe('Storage', async () => { 81 | it('Successfully transfers to internal actor', async () => { 82 | internalActors.push(tokenHolder2); 83 | await testUtilityBrandedToken.registerInternalActors( 84 | internalActors, 85 | { from: worker }, 86 | ); 87 | assert.strictEqual( 88 | (await testUtilityBrandedToken.balanceOf(tokenHolder2)).cmp( 89 | web3.utils.toBN(0), 90 | ), 91 | 0, 92 | 'Balance of tokenholder2 should be zero', 93 | ); 94 | 95 | await testUtilityBrandedToken.transferFrom( 96 | tokenHolder1, 97 | tokenHolder2, 98 | amount, 99 | { from: tokenHolder3 }, 100 | ); 101 | 102 | assert.strictEqual( 103 | (await testUtilityBrandedToken.balanceOf(tokenHolder2)).cmp( 104 | web3.utils.toBN(amount), 105 | ), 106 | 0, 107 | `Balance of tokenholder should be ${amount}`, 108 | ); 109 | }); 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/utility_branded_token/utils.js: -------------------------------------------------------------------------------- 1 | // Copyright 2018 OST.com Ltd. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 'use strict'; 17 | 18 | const config = require('../test_lib/config'); 19 | 20 | const TestUtilityBrandedToken = artifacts.require('TestUtilityBrandedToken'); 21 | const EIP20TokenMock = artifacts.require('EIP20TokenMock'); 22 | const MockOrganization = artifacts.require('MockOrganization'); 23 | 24 | /** 25 | * Setup UtilityBrandedToken. 26 | */ 27 | module.exports.setupUtilityBrandedToken = async (accountProvider, internalActor) => { 28 | const SYMBOL = 'MOCK'; 29 | const NAME = 'Mock Token'; 30 | const { decimals: DECIMALS } = config; 31 | 32 | const { 33 | mockOrganization, 34 | worker, 35 | organization, 36 | } = await this.setupOrganization(accountProvider); 37 | 38 | const brandedToken = await EIP20TokenMock.new( 39 | SYMBOL, 40 | NAME, 41 | DECIMALS, 42 | { from: organization }, 43 | ); 44 | 45 | const testUtilityBrandedToken = await TestUtilityBrandedToken.new( 46 | brandedToken.address, 47 | SYMBOL, 48 | NAME, 49 | DECIMALS, 50 | mockOrganization.address, 51 | { from: organization }, 52 | ); 53 | 54 | await testUtilityBrandedToken.registerInternalActors( 55 | internalActor, 56 | { from: worker }, 57 | ); 58 | 59 | return { 60 | testUtilityBrandedToken, worker, organization, 61 | }; 62 | }; 63 | 64 | /** 65 | * Creates an instance of MockOrganization contract and sets worker. 66 | */ 67 | module.exports.setupOrganization = async (accountProvider) => { 68 | const worker = accountProvider.get(); 69 | const organization = accountProvider.get(); 70 | 71 | const mockOrganization = await MockOrganization.new( 72 | organization, 73 | worker, 74 | ); 75 | 76 | return { 77 | mockOrganization, worker, organization, 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /tools/build_package.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Copyright 2019 OpenST Ltd. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | // ---------------------------------------------------------------------------- 18 | // 19 | // http://www.simpletoken.org/ 20 | // 21 | // ---------------------------------------------------------------------------- 22 | 23 | /** 24 | * @file This file runs as part of the npm packaging process. 25 | * 26 | * It reads a set number of contracts from the truffle build directory and 27 | * extracts ABI and BIN of each contract. The extracted information is added to 28 | * a new object that is finally serialized to disk. That JSON file will be 29 | * exported by this package. 30 | * 31 | * To add a contract to the published package, add its name to array of contract 32 | * names. 33 | */ 34 | 35 | const fs = require('fs'); 36 | const path = require('path'); 37 | 38 | const contractNames = [ 39 | 'BrandedToken', 40 | 'CoGatewayUtilityTokenInterface', 41 | 'EIP20Interface', 42 | 'EIP20Token', 43 | 'GatewayComposer', 44 | 'GatewayInterface', 45 | 'OrganizationInterface', 46 | 'Organized', 47 | 'UtilityBrandedToken', 48 | 'UtilityTokenInterface', 49 | ]; 50 | 51 | const contracts = {}; 52 | 53 | contractNames.forEach((contract) => { 54 | const contractPath = path.join( 55 | __dirname, 56 | `../build/contracts/${contract}.json`, 57 | ); 58 | 59 | if (!fs.existsSync(contractPath)) { 60 | throw new Error( 61 | `Cannot read file ${contractPath}.` 62 | + 'Truffle compile must be run before building the package.' 63 | + 'That should be done automatically when running `npm publish`.', 64 | ); 65 | } 66 | 67 | const contractFile = fs.readFileSync(contractPath); 68 | const metaData = JSON.parse(contractFile); 69 | 70 | contracts[contract] = {}; 71 | contracts[contract].abi = metaData.abi; 72 | 73 | if (metaData.bytecode !== '0x') { 74 | contracts[contract].bin = metaData.bytecode; 75 | } 76 | }); 77 | 78 | fs.writeFileSync('dist/contracts.json', JSON.stringify(contracts)); 79 | -------------------------------------------------------------------------------- /tools/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CONTRACTDIR=./contracts/*.sol 4 | ABIDIRUTILITY=./contracts/abi 5 | BINDIRVALUE=./contracts/bin 6 | 7 | mkdir -p "$ABIDIRUTILITY" 8 | mkdir -p "$BINDIRVALUE" 9 | 10 | for filename in $CONTRACTDIR; do 11 | echo "" 12 | echo "Compiling ${filename}" 13 | echo "" 14 | solc --abi --optimize --optimize-runs 200 --overwrite ${filename} -o $ABIDIRUTILITY 15 | solc --bin --optimize --optimize-runs 200 --overwrite ${filename} -o $BINDIRVALUE 16 | done -------------------------------------------------------------------------------- /tools/runGanacheCli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | node_modules/.bin/ganache-cli \ 3 | --accounts=100 \ 4 | --defaultBalanceEther=100 \ 5 | --gasLimit 0xfffffffffff 6 | -------------------------------------------------------------------------------- /tools/test_range.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019 OpenST Ltd. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | # ---------------------------------------------------------------------------- 18 | # 19 | # http://www.simpletoken.org/ 20 | # 21 | # ---------------------------------------------------------------------------- 22 | 23 | ### 24 | # Runs tests sequentially for a range of decimal values. 25 | # 26 | # Example run with decimals 12 - 18 (inclusive): 27 | # 28 | # ```bash 29 | # npm run test:range -- 12 18 30 | # ``` 31 | # 32 | # You can provide only one argument and the tests will run for that specific 33 | # decimal. 34 | ### 35 | 36 | # Tracking the exit code to run further tests if they fail for a spcefic decimal. 37 | EXIT_CODE=0 38 | 39 | # Tracking failed decimals for error output. 40 | FAILED_DECIMALS="" 41 | 42 | function handle_error { 43 | # On first iteration, no extra comma 44 | if [ $EXIT_CODE -eq 0 ]; 45 | then 46 | FAILED_DECIMALS="$1" 47 | else 48 | FAILED_DECIMALS="${FAILED_DECIMALS}, $1" 49 | fi 50 | EXIT_CODE=1 51 | } 52 | 53 | function handle_exit { 54 | if [ $EXIT_CODE -ne 0 ]; 55 | then 56 | echo "" 57 | echo "### Errors for the following decimals:" 58 | echo "${FAILED_DECIMALS}" 59 | echo "" 60 | else 61 | echo "" 62 | echo "### Done" 63 | echo "" 64 | fi 65 | 66 | exit $EXIT_CODE 67 | } 68 | 69 | echo "" 70 | 71 | if [ $# -ne 1 ] && [ $# -ne 2 ]; 72 | then 73 | echo "Wrong number of parameters given." 74 | echo "Run with two arguments: start and end of range inclusive." 75 | echo "Example:" 76 | echo "npm run test:range -- 16 20" 77 | echo "" 78 | echo "If you provide only one argument, the tests will be run for that value." 79 | echo "" 80 | exit 1 81 | fi 82 | 83 | # Start and end values should be provided on the command line. 84 | START=$1 85 | 86 | if [ $# -eq 1 ]; 87 | then 88 | END=$START 89 | else 90 | END=$2 91 | fi 92 | 93 | for DECIMALS in $(seq "${START}" "${END}"); 94 | do 95 | echo "### Running tests with ${DECIMALS} decimals." 96 | export OPENST_DECIMALS=$DECIMALS 97 | npm test || handle_error $DECIMALS 98 | done 99 | 100 | handle_exit 101 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: 'localhost', 5 | network_id: '*', 6 | port: 8545, 7 | gas: 12000000, 8 | gasPrice: 0x01, 9 | }, 10 | }, 11 | coverage: { 12 | host: 'localhost', 13 | network_id: '*', 14 | port: 8555, // <-- If you change this, also set the port option in .solcover.js. 15 | gas: 0xfffffffffff, // <-- Use this high gas value 16 | gasPrice: 0x01, // <-- Use this low gas price 17 | }, 18 | solc: { 19 | optimizer: { 20 | enabled: true, 21 | // set to same number of runs as openst-platform 22 | // so that integration tests 23 | // give accurate gas measurements 24 | runs: 200, 25 | }, 26 | }, 27 | }; 28 | --------------------------------------------------------------------------------