Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
manologr89 committed Sep 14, 2018
0 parents commit cad2f30
Show file tree
Hide file tree
Showing 17 changed files with 511 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["es2015", "stage-2", "stage-3"]
}
7 changes: 7 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copy to .env and set these

# Value without 0x
KOVAN_PRIV=

# Value without 0x
MAINNET_PRIV=
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
node_modules/
build
environments/
*.sol.js
environments/
.idea
package-lock.json

# test
xunit_testresults.xml

# test coverage
scTopics
coverage/
coverageEnv/
coverage.json

.env
22 changes: 22 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2018

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# How to use
Download/clone this repo, open a terminal in the folder and run:

```
npm install
```

Then, use truffle to deploy and call contracts through a truffle console.

Option 1. If you are running your local node connect to it like this:

```
npm run console --network development
```
or try
```
truffle console --network development
```

Option 2. You can use Infura nodes:
1. Ensure you provide private key for truffle to sign your transactions. Create `.env` file with the key of the account to use. Use `.env.template` as a template.
2. Then use `mainnet` or `kovan` network. E.g. `truffle console --network kovan`

# Deploy a new token

Setup your token parameters (name, symbol and decimals) in Controller.sol, your decimals and totalSupply in migrations/2_deploy_contracts.js. Then, in the truffle console you have open, run `migrate`.
you should see something like
```
Deploying Controller...
... 0xasdsadasdadaa6250f9f1a30a9fbb24068efd68b5656565656b65a4ec
Controller: 0xbadadsaasdaasde99a3bb44eaea4c11835454538c
... 0x0asdadssadasc0a6aa64f23d6888d46645454545456adc9d4a0c3bb12a49d
0
```
When its done, it will still be blinking in the console, click the up arrow to get back to truffle console
You will now have the token contract address next to Proxy: in the console
and the controller address next to Controller:

Make a note of both these addresses.

# Usage

If you want to create a transaction with your token, you have to use a Controller facade on top of the Proxy contract,
put the token contract address between the quotes:
```
var ctrl = Controller.at("proxy.address")
```

Then, you can use any of the token functions, like minting, put the address between the quotes:
```
ctrl.mint("holder address", amount)
```

to mint tokens be aware of the decimals. For example if you gonna mint 3 tokens. You would write
3*10**decimals
or
3*10**18
if your token got 18 decimals.
39 changes: 39 additions & 0 deletions contracts/Controller.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

pragma solidity ^0.4.23;

import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
import "zeppelin-solidity/contracts/token/ERC20/MintableToken.sol";
import "zeppelin-solidity/contracts/token/ERC20/PausableToken.sol";

contract Controller is MintableToken, PausableToken {
address public thisAddr; // matches delegation slot in proxy
uint256 public cap; // the max cap of this token
string public constant name = "COIN"; // solium-disable-line uppercase
string public constant symbol = "COIN"; // solium-disable-line uppercase
uint8 public constant decimals = 18; // solium-disable-line uppercase

/**
* @dev Function to initialize storage, only callable from proxy.
* @param _controller The address where code is loaded from through delegatecall
* @param _cap The cap that should be set for the token
*/
function initialize(address _controller, uint256 _cap) onlyOwner public {
require(cap == 0);
require(_cap > 0);
require(thisAddr == _controller);
cap = _cap;
totalSupply_ = 0;
}

/**
* @dev Function to mint tokens
* @param _to The address that will receive the minted tokens.
* @param _amount The amount of tokens to mint.
* @return A boolean that indicates if the operation was successful.
*/
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
require(cap > 0);
require(totalSupply_.add(_amount) <= cap);
return super.mint(_to, _amount);
}
}
42 changes: 42 additions & 0 deletions contracts/Delegatable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pragma solidity ^0.4.23;

/**
* @title Delegatable
* ownable contract extended by one more variable
*/
contract Delegatable {
address empty1; // unknown slot
address empty2; // unknown slot
address empty3; // unknown slot
address public owner; // matches owner slot in controller
address public delegation; // matches thisAddr slot in controller

event DelegationTransferred(address indexed previousDelegate, address indexed newDelegation);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

modifier onlyOwner() {
require(msg.sender == owner);
_;
}

/**
* @dev Allows owner to transfer delegation of the contract to a newDelegation.
* @param newDelegation The address to transfer delegation to.
*/
function transferDelegation(address newDelegation) public onlyOwner {
require(newDelegation != address(0));
emit DelegationTransferred(delegation, newDelegation);
delegation = newDelegation;
}

/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}

}
25 changes: 25 additions & 0 deletions contracts/DelegateProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity ^0.4.18;


contract DelegateProxy {

/**
* @dev Performs a delegatecall and returns whatever the delegatecall returned (entire context execution will return!)
* @param _dst Destination address to perform the delegatecall
* @param _calldata Calldata for the delegatecall
*/
function delegatedFwd(address _dst, bytes _calldata) internal {
assembly {
let result := delegatecall(sub(gas, 10000), _dst, add(_calldata, 0x20), mload(_calldata), 0, 0)
let size := returndatasize

let ptr := mload(0x40)
returndatacopy(ptr, 0, size)

// revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas.
// if the call returned error data, forward it
switch result case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
23 changes: 23 additions & 0 deletions contracts/Migrations.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma solidity ^0.4.18;

contract Migrations {
address public owner;
uint public last_completed_migration;

modifier restricted() {
if (msg.sender == owner) _;
}

constructor() public {
owner = msg.sender;
}

function setCompleted(uint completed) public restricted {
last_completed_migration = completed;
}

function upgrade(address new_address) public restricted {
Migrations upgraded = Migrations(new_address);
upgraded.setCompleted(last_completed_migration);
}
}
31 changes: 31 additions & 0 deletions contracts/Proxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
pragma solidity ^0.4.23;

import "./DelegateProxy.sol";
import "./Delegatable.sol";

/**
* @title Proxy
* Basic proxy implementation to controller
*/
contract Proxy is Delegatable, DelegateProxy {

/**
* @dev Function to invoke all function that are implemented in controler
*/
function () public {
delegatedFwd(delegation, msg.data);
}

/**
* @dev Function to initialize storage of proxy
* @param _controller The address of the controller to load the code from
* @param _cap Max amount of tokens that should be mintable
*/
function initialize(address _controller, uint256 _cap) public {
require(owner == 0);
owner = msg.sender;
delegation = _controller;
delegatedFwd(_controller, msg.data);
}

}
3 changes: 3 additions & 0 deletions migrations/1_initial_migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = function(deployer) {

};
21 changes: 21 additions & 0 deletions migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const Proxy = artifacts.require('./Proxy.sol');
const Controller = artifacts.require('./Controller.sol');

const decimals = 18;
const supply = 10000000000000;

module.exports = async function(deployer) {
// deploy proxy
await deployer.deploy(Proxy);
const proxy = await Proxy.deployed();
// deploy controller
await deployer.deploy(Controller);
const controller = await Controller.deployed();
// create binding of proxy with controller interface
let token = Controller.at(proxy.address);
// use binding
await token.initialize(controller.address, supply*(10**decimals));
// check result
let cap = await token.cap();
console.log(cap.toNumber());
};
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "icomalta-token",
"license": "MIT",
"main": "truffle.js",
"scripts": {
"test": "npm run ganache-cli:dev && truffle test --network rpc",
"ganache-cli:dev": "scripts/ganache-cli.sh"
},
"devDependencies": {
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.18.0",
"babel-preset-stage-2": "^6.18.0",
"babel-preset-stage-3": "^6.17.0",
"babel-register": "^6.23.0",
"truffle-privatekey-provider": "0.0.6",
"dotenv": "^5.0.1",
"ganache-cli": "^6.0.3",
"solium": "^1.1.2",
"truffle": "4.0.6"
},
"dependencies": {
"bignumber.js": "^4.0.1",
"zeppelin-solidity": "^1.6.0"
}
}
31 changes: 31 additions & 0 deletions scripts/ganache-cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash

# Exit script as soon as a command fails.
set -o errexit

if [ "$SOLIDITY_COVERAGE" = true ]; then
testrpc_port=8555
else
testrpc_port=8545
fi

testrpc_running() {
nc -z localhost "$testrpc_port"
}

start_testrpc() {
if [ "$SOLIDITY_COVERAGE" = true ]; then
node_modules/.bin/testrpc-sc -i 16 --gasLimit 0xfffffffffff --port "$testrpc_port" > /dev/null &
else
node_modules/.bin/ganache-cli -i 15 --gasLimit 50000000 > /dev/null &
fi

testrpc_pid=$!
}

if testrpc_running; then
echo "Using existing testrpc instance at port $testrpc_port"
else
echo "Starting our own testrpc instance at port $testrpc_port"
start_testrpc
fi
26 changes: 26 additions & 0 deletions test/helpers/assertThrow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function assertError(error, s, message) {
assert.isAbove(error.message.search(s), -1, message);
}

async function assertThrows(codeBlock, message, errorCode) {
try {
await codeBlock()
} catch (e) {
return assertError(e, errorCode, message)
}
assert.fail('should have thrown before')
}

module.exports = {
async assertJump(codeBlock, message = 'should have failed with invalid JUMP') {
return assertThrows(codeBlock, message, 'invalid JUMP')
},

async assertInvalidOpcode(codeBlock, message = 'should have failed with invalid opcode') {
return assertThrows(codeBlock, message, 'invalid opcode')
},

async assertRevert(codeBlock, message = 'should have failed by reverting') {
return assertThrows(codeBlock, message, 'revert')
},
}
Loading

0 comments on commit cad2f30

Please sign in to comment.