Skip to content

Commit d39bda7

Browse files
committed
setup micro fragments
0 parents  commit d39bda7

44 files changed

Lines changed: 11601 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.eslintrc.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
module.exports = {
2+
"extends": ["google", "standard", "plugin:prettier/recommended", "mocha"],
3+
"env": {
4+
"mocha": true,
5+
"node": true,
6+
"es6": true,
7+
},
8+
"parserOptions": {
9+
"ecmaVersion": 8,
10+
},
11+
"globals": {
12+
"artifacts": true,
13+
"assert": true,
14+
"contract": true,
15+
"expect": true,
16+
"Promise": true,
17+
"web3": true,
18+
},
19+
"plugins": ["prettier", "spellcheck", "chai-friendly"],
20+
"rules": {
21+
"prettier/prettier": 0,
22+
"require-jsdoc": 0,
23+
"semi": [2, "always"],
24+
"prefer-const": 2,
25+
"no-unused-expressions": 0,
26+
"chai-friendly/no-unused-expressions": 2,
27+
"spellcheck/spell-checker": [
28+
2,
29+
{
30+
"comments": true,
31+
"strings": true,
32+
"identifiers": true,
33+
"lang": "en_US",
34+
"skipWords": [
35+
// misc
36+
"deployer", "http", "https", "github", "chai", "argv", "evm",
37+
"jsonrpc", "timestamp", "uint256", "erc20", "bignumber", "lodash",
38+
"arg", "npm", "seedrandom", "eql", "sinon", "yaml", "promisify",
39+
"passcode", "geth", "rpc", "rpcmsg","stdev", "stochasm", "aggregator",
40+
"whitelist",
41+
42+
// shorthand
43+
"eth", "args", "util", "utils", "msg", "prev", "bal",
44+
"init", "params", "mul", "async", "vals", "fns", "addrs",
45+
"fns", "num", "dev", "pre","abi", "gte","rnd", "chk", "bals", "lte",
46+
"addr",
47+
48+
// project-specific
49+
"rebase", "gons", "frg", "rng", "blockchain", "minlot",
50+
"redemptions", "rebased", "ganache", "ethclient",
51+
"bytecode", "Binance",
52+
53+
// names
54+
"nithin",
55+
],
56+
"skipIfMatch": [
57+
"http(s)?://[^s]*",
58+
"Sha3",
59+
"0x*",
60+
],
61+
"minLength": 3
62+
}
63+
],
64+
},
65+
};

.gitignore

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Generated files
2+
build
3+
dist
4+
5+
### Emacs ##
6+
*~
7+
\#*\#
8+
.\#*
9+
10+
#
11+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
12+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
13+
#
14+
15+
# User-specific stuff:
16+
.idea/**/workspace.xml
17+
.idea/**/tasks.xml
18+
.idea/dictionaries
19+
20+
# Sensitive or high-churn files:
21+
.idea/**/dataSources/
22+
.idea/**/dataSources.ids
23+
.idea/**/dataSources.local.xml
24+
.idea/**/sqlDataSources.xml
25+
.idea/**/dynamic.xml
26+
.idea/**/uiDesigner.xml
27+
28+
# Gradle:
29+
.idea/**/gradle.xml
30+
.idea/**/libraries
31+
32+
# CMake
33+
cmake-build-debug/
34+
cmake-build-release/
35+
36+
# Mongo Explorer plugin:
37+
.idea/**/mongoSettings.xml
38+
39+
## File-based project format:
40+
*.iws
41+
42+
## Plugin-specific files:
43+
44+
# IntelliJ
45+
out/
46+
47+
# mpeltonen/sbt-idea plugin
48+
.idea_modules/
49+
50+
# JIRA plugin
51+
atlassian-ide-plugin.xml
52+
53+
# Cursive Clojure plugin
54+
.idea/replstate.xml
55+
56+
# Crashlytics plugin (for Android Studio and IntelliJ)
57+
com_crashlytics_export_strings.xml
58+
crashlytics.properties
59+
crashlytics-build.properties
60+
fabric.properties
61+
62+
# NodeJS dependencies
63+
node_modules/*
64+
65+
# ES-Lint
66+
.eslintcache

.travis.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
dist: trusty
2+
sudo: false
3+
language: node_js
4+
node_js:
5+
- "8"
6+
cache:
7+
directories:
8+
- node_modules
9+
script:
10+
- npm run lint
11+
- npm run test
12+
notifications:
13+
email:
14+
15+
slack: fragmentsorg:2bN0L0FCZZ0illBRyPucRZkV

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Micro Fragments
2+
Micro Fragments protocol smart contracts on Ethereum.
3+
4+
# Getting started
5+
```bash
6+
# Install dependencies
7+
npm install
8+
```
9+
10+
# Useful scripts
11+
``` bash
12+
# You can use the following commands to start/stop local ganache chain
13+
npm run blockchain:start
14+
npm run blockchain:stop
15+
# Lint code
16+
npm run lint
17+
# track gas utilization
18+
npm run trackGasUtilization
19+
```
20+
21+
# Testing
22+
```
23+
# Run Unit Tests
24+
npm test
25+
26+
# Run unit tests in isolation
27+
npm run truffle test test/test_file.js
28+
```

contracts/MicroFragments.sol

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
pragma solidity 0.4.24;
2+
3+
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
4+
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
5+
import "openzeppelin-solidity/contracts/token/ERC20/DetailedERC20.sol";
6+
7+
/**
8+
* @title Micro Fragments ERC20 token
9+
* @notice https://www.fragments.org/protocol/
10+
*
11+
* @dev Fragment balances are internally represented with a hidden denomination, 'gons'. We support
12+
* splitting the currency in expansion by changing the exchange rate between the hidden 'gon'
13+
* currency and the public 'fragments' currency. This exchange rate is determined by the
14+
* internal properties 'maxTotalGons' and 'totalSupply_'.
15+
*
16+
* Anytime there is division, there is a risk of numerical instability from rounding errors. In
17+
* order to minimize this risk, we adhere to the following guidelines:
18+
* - The conversion rate adopted is the number of gons that equals 1 fragment. The inverse
19+
* rate must not be used--maxTotalGons is always the numerator and totalSupply_ is
20+
* always the denominator. (i.e. If you want to convert gons to fragments instead of
21+
* multiplying by the inverse rate, you should divide by the normal rate)
22+
* - Gon balances converted into fragments are always rounded down (truncated).
23+
* - Fragment values converted to gon values (such as in transfers) are chosen such at the
24+
* below guarantees are upheld.
25+
*
26+
* We make the following guarantees:
27+
* - If address 'A' transfers x fragments to address 'B'. A's resulting external balance will
28+
* be decreased by precisely x fragments, and B's external balance will be precisely
29+
* increased by x fragments.
30+
*
31+
* We do not guarantee that the sum of all balances equals the result of calling totalSupply().
32+
* This is because, for any conversion function 'f()' that has non-zero rounding error,
33+
* f(x0) + f(x1) + ... + f(xn) is not always equal to f(x0 + x1 + ... xn).
34+
*
35+
* 'The Introduction of the Euro and the Rounding of Currency Amounts (1999)' is a good starting
36+
* reference for practices related to currency conversions.
37+
* http://ec.europa.eu/economy_finance/publications/pages/publication1224_en.pdf
38+
*/
39+
contract MicroFragments is DetailedERC20("Fragments", "mFRGD", 2), Ownable {
40+
using SafeMath for uint256;
41+
42+
event Rebase(uint256 indexed epoch, int256 supplyDelta);
43+
44+
uint256 private totalSupply_ = 1000;
45+
46+
mapping(address => uint256) private gonBalances;
47+
48+
// These two numbers determine the gons-fragments exchange rate. (numerator and denominator,
49+
//respectively). The effective exchange rate ONLY changes on expansion.
50+
uint256 private maxTotalGons = 1 << 170;
51+
52+
// This is denominated in Fragments, because the gons-fragments conversion might change before
53+
// it's fully paid.
54+
mapping (address => mapping (address => uint256)) internal allowedFragments;
55+
56+
uint256 public epoch = 0;
57+
58+
constructor() public {
59+
gonBalances[msg.sender] = maxTotalGons;
60+
}
61+
62+
/**
63+
* @dev Notifies Fragments contract about a new rebase cycle.
64+
* @param supplyDelta The number of new fragment tokens to add into circulation/remove from circulation.
65+
*/
66+
function rebase(int256 supplyDelta) public onlyOwner {
67+
if (supplyDelta < 0) {
68+
totalSupply_ = totalSupply_.sub(uint256(supplyDelta));
69+
require(totalSupply_ > 0);
70+
} else {
71+
totalSupply_ = totalSupply_.add(uint256(supplyDelta));
72+
}
73+
74+
epoch++;
75+
emit Rebase(epoch, supplyDelta);
76+
}
77+
78+
/**
79+
* @return The total number of fragments.
80+
*/
81+
function totalSupply() public view returns (uint256) {
82+
return totalSupply_;
83+
}
84+
85+
/**
86+
* @param who The address to query.
87+
* @return The balance of the specified address.
88+
*/
89+
function balanceOf(address who) public view returns (uint256) {
90+
return gonBalances[who].div(maxTotalGons.div(totalSupply_));
91+
}
92+
93+
/**
94+
* @dev Transfer tokens to a specified address.
95+
* @param to The address to transfer to.
96+
* @param value The amount to be transferred.
97+
* @return True on success, false otherwise.
98+
*/
99+
function transfer(address to, uint256 value) public returns (bool) {
100+
transferHelper(msg.sender, to, value);
101+
return true;
102+
}
103+
104+
/**
105+
* @dev Function to check the amount of tokens that an owner has allowed to a spender.
106+
* @param owner The address which owns the funds.
107+
* @param spender The address which will spend the funds.
108+
* @return The number of tokens still available for the spender.
109+
*/
110+
function allowance(address owner, address spender) public view returns (uint256) {
111+
return allowedFragments[owner][spender];
112+
}
113+
114+
/**
115+
* @dev Transfer tokens from one address to another.
116+
* @param from The address you want to send tokens from.
117+
* @param to The address you want to transfer to.
118+
* @param value The amount of tokens to be transferred.
119+
*/
120+
function transferFrom(address from, address to, uint256 value) public returns (bool) {
121+
require(value <= allowedFragments[from][msg.sender]);
122+
allowedFragments[from][msg.sender] = allowedFragments[from][msg.sender].sub(value);
123+
transferHelper(from, to, value);
124+
return true;
125+
}
126+
127+
/**
128+
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
129+
*
130+
* Beware that changing an allowance with this method brings the risk that someone may use both the old
131+
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
132+
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
133+
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
134+
* @param spender The address which will spend the funds.
135+
* @param value The amount of tokens to be spent.
136+
*/
137+
function approve(address spender, uint256 value) public returns (bool) {
138+
allowedFragments[msg.sender][spender] = value;
139+
emit Approval(msg.sender, spender, value);
140+
return true;
141+
}
142+
143+
/**
144+
* @dev Increase the amount of tokens that an owner has allowed to a spender.
145+
*
146+
* approve should be called when allowed[_spender] == 0. To increment
147+
* allowed value is better to use this function to avoid 2 calls (and wait until
148+
* the first transaction is mined)
149+
* From MonolithDAO Token.sol
150+
* @param spender The address which will spend the funds.
151+
* @param addedValue The amount of tokens to increase the allowance by.
152+
*/
153+
function increaseApproval(address spender, uint addedValue) public returns (bool) {
154+
allowedFragments[msg.sender][spender] = allowedFragments[msg.sender][spender].add(addedValue);
155+
emit Approval(msg.sender, spender, allowedFragments[msg.sender][spender]);
156+
return true;
157+
}
158+
159+
/**
160+
* @dev Decrease the amount of tokens that an owner has allowed to a spender.
161+
*
162+
* approve should be called when allowed[_spender] == 0. To decrement
163+
* allowed value is better to use this function to avoid 2 calls (and wait until
164+
* the first transaction is mined)
165+
* From MonolithDAO Token.sol
166+
* @param spender The address which will spend the funds.
167+
* @param subtractedValue The amount of tokens to decrease the allowance by.
168+
*/
169+
function decreaseApproval(address spender, uint subtractedValue) public returns (bool) {
170+
uint oldValue = allowedFragments[msg.sender][spender];
171+
if (subtractedValue > oldValue) {
172+
allowedFragments[msg.sender][spender] = 0;
173+
} else {
174+
allowedFragments[msg.sender][spender] = oldValue.sub(subtractedValue);
175+
}
176+
emit Approval(msg.sender, spender, allowedFragments[msg.sender][spender]);
177+
return true;
178+
}
179+
180+
/**
181+
* @dev Transfers a number of gons between from and to, such that the resulting balances match
182+
* the expectations when denominated in fragments.
183+
*/
184+
function transferHelper(address from, address to, uint256 value) private {
185+
require(to != address(0));
186+
187+
uint256 gonsPerFragment = maxTotalGons.div(totalSupply_);
188+
uint256 senderMod = gonBalances[from] % gonsPerFragment;
189+
uint256 receiverMod = gonBalances[to] % gonsPerFragment;
190+
uint256 baseAmt = value.mul(gonsPerFragment);
191+
192+
uint256 senderGonMinAmt = baseAmt.sub(gonsPerFragment.sub(senderMod).sub(1));
193+
uint256 senderGonMaxAmt = baseAmt.add(senderMod);
194+
uint256 receiverGonMinAmt = baseAmt.sub(receiverMod);
195+
uint256 receiverGonMaxAmt = baseAmt.add(gonsPerFragment.sub(receiverMod).sub(1));
196+
197+
// Choose the max of the minimum viable transfer amounts on each side.
198+
uint256 gonValue = (senderGonMinAmt >= receiverGonMinAmt) ? senderGonMinAmt : receiverGonMinAmt;
199+
200+
assert(gonValue <= senderGonMaxAmt);
201+
assert(gonValue <= receiverGonMaxAmt);
202+
203+
require(gonValue <= gonBalances[from]);
204+
gonBalances[from] = gonBalances[from].sub(gonValue);
205+
gonBalances[to] = gonBalances[to].add(gonValue);
206+
emit Transfer(from, to, value);
207+
}
208+
}

0 commit comments

Comments
 (0)