-
Notifications
You must be signed in to change notification settings - Fork 33
/
Ambix.sol
117 lines (99 loc) · 3.76 KB
/
Ambix.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
pragma solidity ^0.4.24;
import 'openzeppelin-solidity/contracts/token/ERC20/StandardBurnableToken.sol';
import 'openzeppelin-solidity/contracts/ownership/Ownable.sol';
/**
@dev Ambix contract is used for morph Token set to another
Token's by rule (recipe). In distillation process given
Token's are burned and result generated by emission.
The recipe presented as equation in form:
(N1 * A1 & N'1 * A'1 & N''1 * A''1 ...)
| (N2 * A2 & N'2 * A'2 & N''2 * A''2 ...) ...
| (Nn * An & N'n * A'n & N''n * A''n ...)
= M1 * B1 & M2 * B2 ... & Mm * Bm
where A, B - input and output tokens
N, M - token value coeficients
n, m - input / output dimetion size
| - is alternative operator (logical OR)
& - is associative operator (logical AND)
This says that `Ambix` should receive (approve) left
part of equation and send (transfer) right part.
*/
contract Ambix is Ownable {
address[][] public A;
uint256[][] public N;
address[] public B;
uint256[] public M;
/**
* @dev Append token recipe source alternative
* @param _a Token recipe source token addresses
* @param _n Token recipe source token counts
**/
function appendSource(
address[] _a,
uint256[] _n
) external onlyOwner {
require(_a.length == _n.length);
for (uint256 i = 0; i < _a.length; ++i)
require(_a[i] != 0);
A.push(_a);
N.push(_n);
}
/**
* @dev Set sink of token recipe
* @param _b Token recipe sink token list
* @param _m Token recipe sink token counts
*/
function setSink(
address[] _b,
uint256[] _m
) external onlyOwner{
require(_b.length == _m.length);
for (uint256 i = 0; i < _b.length; ++i)
require(_b[i] != 0);
B = _b;
M = _m;
}
/**
* @dev Run distillation process
* @param _ix Source alternative index
*/
function run(uint256 _ix) public {
require(_ix < A.length);
uint256 i;
if (N[_ix][0] > 0) {
// Static conversion
StandardBurnableToken token = StandardBurnableToken(A[_ix][0]);
// Token count multiplier
uint256 mux = token.allowance(msg.sender, this) / N[_ix][0];
require(mux > 0);
// Burning run
for (i = 0; i < A[_ix].length; ++i) {
token = StandardBurnableToken(A[_ix][i]);
require(token.transferFrom(msg.sender, this, mux * N[_ix][i]));
token.burn(mux * N[_ix][i]);
}
// Transfer up
for (i = 0; i < B.length; ++i) {
token = StandardBurnableToken(B[i]);
require(token.transfer(msg.sender, M[i] * mux));
}
} else {
// Dynamic conversion
// Let source token total supply is finite and decrease on each conversion,
// just convert finite supply of source to tokens on balance of ambix.
// dynamicRate = balance(sink) / total(source)
// Is available for single source and single sink only
require(A[_ix].length == 1 && B.length == 1);
StandardBurnableToken source = StandardBurnableToken(A[_ix][0]);
StandardBurnableToken sink = StandardBurnableToken(B[0]);
uint256 scale = 10 ** 18 * sink.balanceOf(this) / source.totalSupply();
uint256 allowance = source.allowance(msg.sender, this);
require(allowance > 0);
require(source.transferFrom(msg.sender, this, allowance));
source.burn(allowance);
uint256 reward = scale * allowance / 10 ** 18;
require(reward > 0);
require(sink.transfer(msg.sender, reward));
}
}
}