Merge branch '145-identity' into 150-gas-abstraction
This commit is contained in:
commit
a3a6732e97
|
@ -36,6 +36,7 @@ coverage.json
|
|||
# node
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
package-lock.json
|
||||
|
||||
# other
|
||||
.vs/
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import ERC20Token from 'Embark/contracts/ERC20Token';
|
||||
import React from 'react';
|
||||
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
|
||||
|
||||
class ERC20TokenUI extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
||||
balanceOf: 0,
|
||||
transferTo: "",
|
||||
transferAmount: 0,
|
||||
logs: []
|
||||
}
|
||||
}
|
||||
|
||||
contractAddress(e){
|
||||
e.preventDefault();
|
||||
var tokenAddress = e.target.value;
|
||||
ERC20Token.options.address = tokenAddress;
|
||||
}
|
||||
|
||||
update_transferTo(e){
|
||||
this.setState({transferTo: e.target.value});
|
||||
}
|
||||
|
||||
update_transferAmount(e){
|
||||
this.setState({transferAmount: e.target.value});
|
||||
}
|
||||
|
||||
transfer(e){
|
||||
var to = this.state.transferTo;
|
||||
var amount = this.state.transferAmount;
|
||||
var tx = ERC20Token.methods.transfer(to, amount).send({from: web3.eth.defaultAccount});
|
||||
this._addToLog(ERC20Token.options.address+".transfer(" + to + ", "+amount+")");
|
||||
}
|
||||
|
||||
approve(e){
|
||||
var to = this.state.transferTo;
|
||||
var amount = this.state.transferAmount;
|
||||
var tx = ERC20Token.methods.approve(to, amount).send({from: web3.eth.defaultAccount});
|
||||
this._addToLog(ERC20Token.options.address+".approve(" + to + ", "+amount+")");
|
||||
}
|
||||
|
||||
balanceOf(e){
|
||||
e.preventDefault();
|
||||
var who = e.target.value;
|
||||
if (EmbarkJS.isNewWeb3()) {
|
||||
ERC20Token.methods.balanceOf(who).call()
|
||||
.then(_value => this.setState({balanceOf: _value}))
|
||||
|
||||
} else {
|
||||
ERC20Token.balanceOf(who)
|
||||
.then(_value => this.x({balanceOf: _value}));
|
||||
}
|
||||
this._addToLog(ERC20Token.options.address+".balanceOf(" + who + ")");
|
||||
}
|
||||
|
||||
|
||||
_addToLog(txt){
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
render(){
|
||||
return (<React.Fragment>
|
||||
|
||||
<h2> Set token contract address</h2>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
onChange={(e) => this.contractAddress(e)} />
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
|
||||
<h3> Read account token balance</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<label>
|
||||
Of:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.accountB}
|
||||
onChange={(e) => this.balanceOf(e)} />
|
||||
</label>
|
||||
<label>
|
||||
<HelpBlock><span className="balanceOf">{this.state.balanceOf}</span></HelpBlock>
|
||||
</label>
|
||||
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> Transfer/Approve token balance</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<label>
|
||||
To:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.transferTo}
|
||||
onChange={(e) => this.update_transferTo(e) } />
|
||||
</label>
|
||||
<label>
|
||||
Amount:
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.transferAmount}
|
||||
onChange={(e) => this.update_transferAmount(e) } />
|
||||
</label>
|
||||
<Button bsStyle="primary" onClick={(e) => this.transfer(e)}>Transfer</Button>
|
||||
<Button bsStyle="primary" onClick={(e) => this.approve(e)}>Approve</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> Contract Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ERC20TokenUI;
|
|
@ -0,0 +1,88 @@
|
|||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import TestToken from 'Embark/contracts/TestToken';
|
||||
import React from 'react';
|
||||
import { Form, FormGroup, FormControl, HelpBlock, Button } from 'react-bootstrap';
|
||||
|
||||
class TestTokenUI extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
amountToMint: 100,
|
||||
accountBalance: 0,
|
||||
accountB: web3.eth.defaultAccount,
|
||||
balanceOf: 0,
|
||||
logs: []
|
||||
}
|
||||
}
|
||||
|
||||
handleMintAmountChange(e){
|
||||
this.setState({amountToMint: e.target.value});
|
||||
}
|
||||
|
||||
mint(e){
|
||||
e.preventDefault();
|
||||
|
||||
var value = parseInt(this.state.amountToMint, 10);
|
||||
|
||||
if (EmbarkJS.isNewWeb3()) {
|
||||
TestToken.methods.mint(value).send({from: web3.eth.defaultAccount});
|
||||
} else {
|
||||
TestToken.mint(value);
|
||||
this._addToLog("#blockchain", "TestToken.mint(" + value + ")");
|
||||
}
|
||||
this._addToLog(TestToken.options.address +".mint("+value+").send({from: " + web3.eth.defaultAccount + "})");
|
||||
}
|
||||
|
||||
getBalance(e){
|
||||
e.preventDefault();
|
||||
|
||||
if (EmbarkJS.isNewWeb3()) {
|
||||
TestToken.methods.balanceOf(web3.eth.defaultAccount).call()
|
||||
.then(_value => this.setState({accountBalance: _value}))
|
||||
} else {
|
||||
TestToken.balanceOf(web3.eth.defaultAccount)
|
||||
.then(_value => this.x({valueGet: _value}))
|
||||
}
|
||||
this._addToLog(TestToken.options.address + ".balanceOf(" + web3.eth.defaultAccount + ")");
|
||||
}
|
||||
|
||||
_addToLog(txt){
|
||||
this.state.logs.push(txt);
|
||||
this.setState({logs: this.state.logs});
|
||||
}
|
||||
|
||||
render(){
|
||||
return (<React.Fragment>
|
||||
<h3> 1. Mint Test Token</h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<FormControl
|
||||
type="text"
|
||||
defaultValue={this.state.amountToMint}
|
||||
onChange={(e) => this.handleMintAmountChange(e)} />
|
||||
<Button bsStyle="primary" onClick={(e) => this.mint(e)}>Mint</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> 2. Read your account token balance </h3>
|
||||
<Form inline>
|
||||
<FormGroup>
|
||||
<HelpBlock>Your test token balance is <span className="accountBalance">{this.state.accountBalance}</span></HelpBlock>
|
||||
<Button bsStyle="primary" onClick={(e) => this.getBalance(e)}>Get Balance</Button>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
|
||||
<h3> 3. Contract Calls </h3>
|
||||
<p>Javascript calls being made: </p>
|
||||
<div className="logs">
|
||||
{
|
||||
this.state.logs.map((item, i) => <p key={i}>{item}</p>)
|
||||
}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TestTokenUI;
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
div {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
.logs {
|
||||
background-color: black;
|
||||
font-size: 14px;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: red;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.status-online {
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
margin-top: 4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: mediumseagreen;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
input.form-control {
|
||||
margin: 5px;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Tabs, Tab } from 'react-bootstrap';
|
||||
|
||||
import EmbarkJS from 'Embark/EmbarkJS';
|
||||
import TestTokenUI from './components/testtoken';
|
||||
import ERC20TokenUI from './components/erc20token';
|
||||
|
||||
import './dapp.css';
|
||||
|
||||
class App extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
__embarkContext.execWhenReady(() => {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
_renderStatus(title, available){
|
||||
let className = available ? 'pull-right status-online' : 'pull-right status-offline';
|
||||
return <React.Fragment>
|
||||
{title}
|
||||
<span className={className}></span>
|
||||
</React.Fragment>;
|
||||
}
|
||||
|
||||
render(){
|
||||
return (<div><h3>Status.im Contracts</h3>
|
||||
<Tabs defaultActiveKey={1} id="uncontrolled-tab-example">
|
||||
<Tab eventKey={1} title="TestToken">
|
||||
<TestTokenUI />
|
||||
</Tab>
|
||||
<Tab eventKey={2} title="ERC20Token">
|
||||
<ERC20TokenUI />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(<App></App>, document.getElementById('app'));
|
|
@ -0,0 +1,12 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Status.im - Contracts</title>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
|
||||
</head>
|
||||
<body class="container">
|
||||
<div id="app">
|
||||
</div>
|
||||
<script src="js/dapp.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -9,12 +9,12 @@
|
|||
"maxpeers": 0,
|
||||
"rpcHost": "localhost",
|
||||
"rpcPort": 8545,
|
||||
"rpcCorsDomain": "http://localhost:8000",
|
||||
"rpcCorsDomain": "auto",
|
||||
"account": {
|
||||
"password": "config/development/password"
|
||||
},
|
||||
"targetGasLimit": 8000000,
|
||||
"wsOrigins": "http://localhost:8000",
|
||||
"wsOrigins": "auto",
|
||||
"wsRPC": true,
|
||||
"wsHost": "localhost",
|
||||
"wsPort": 8546,
|
||||
|
|
|
@ -15,6 +15,31 @@
|
|||
],
|
||||
"gas": "auto",
|
||||
"contracts": {
|
||||
"ERC20Receiver": {
|
||||
"deploy": false
|
||||
},
|
||||
"Factory": {
|
||||
"deploy": false
|
||||
},
|
||||
"Instance": {
|
||||
"deploy": false
|
||||
},
|
||||
"UpdatableInstance": {
|
||||
"deploy": false
|
||||
},
|
||||
"DelayedUpdatableInstance": {
|
||||
"deploy": false
|
||||
},
|
||||
"Identity": {
|
||||
"deploy": false
|
||||
},
|
||||
"IdentityKernel": {
|
||||
"deploy": false
|
||||
},
|
||||
"IdentityFactory": {
|
||||
"deploy": true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{
|
||||
"config": {
|
||||
"homesteadBlock": 1
|
||||
"homesteadBlock": 1,
|
||||
"byzantiumBlock": 1,
|
||||
"daoForkSupport": true
|
||||
},
|
||||
"nonce": "0x0000000000000042",
|
||||
"difficulty": "0x0",
|
||||
|
|
|
@ -14,7 +14,7 @@ contract DelayedUpdatableInstance is DelayedUpdatableInstanceStorage, DelegatedC
|
|||
event UpdateCancelled();
|
||||
event UpdateConfirmed(address oldKernel, address newKernel);
|
||||
|
||||
function DelayedUpdatableInstance(address _kernel) public {
|
||||
constructor(address _kernel) public {
|
||||
kernel = _kernel;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,4 +17,6 @@ contract DelayedUpdatableInstanceStorage {
|
|||
uint256 activation;
|
||||
}
|
||||
// protected zone end
|
||||
|
||||
constructor() internal { }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.21;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,10 @@ pragma solidity ^0.4.21;
|
|||
* Important to avoid overwriting wrong storage pointers is that never define storage to this contract
|
||||
*/
|
||||
contract DelegatedCall {
|
||||
|
||||
constructor() internal {
|
||||
|
||||
}
|
||||
/**
|
||||
* @dev delegates the call of this function
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
import "../common/Controlled.sol";
|
||||
|
||||
|
@ -19,7 +19,7 @@ contract Factory is Controlled {
|
|||
uint256 latestUpdate;
|
||||
address latestKernel;
|
||||
|
||||
function Factory(address _kernel)
|
||||
constructor(address _kernel)
|
||||
public
|
||||
{
|
||||
_setKernel(_kernel);
|
||||
|
|
|
@ -10,7 +10,7 @@ import "./DelegatedCall.sol";
|
|||
*/
|
||||
contract Instance is InstanceStorage, DelegatedCall {
|
||||
|
||||
function Instance(address _kernel) public {
|
||||
constructor(address _kernel) public {
|
||||
kernel = _kernel;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -12,4 +12,5 @@ contract InstanceStorage {
|
|||
// protected zone start (InstanceStorage vars)
|
||||
address public kernel;
|
||||
// protected zone end
|
||||
constructor() internal { }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
import "./Instance.sol";
|
||||
|
||||
|
@ -12,7 +12,7 @@ contract UpdatableInstance is Instance {
|
|||
|
||||
event InstanceUpdated(address oldKernel, address newKernel);
|
||||
|
||||
function UpdatableInstance(address _kernel)
|
||||
constructor(address _kernel)
|
||||
Instance(_kernel)
|
||||
public
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ contract UpdatableInstance is Instance {
|
|||
|
||||
function updateUpdatableInstance(address _kernel) external {
|
||||
require(msg.sender == address(this));
|
||||
InstanceUpdated(kernel, _kernel);
|
||||
emit InstanceUpdated(kernel, _kernel);
|
||||
kernel = _kernel;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,19 +11,21 @@ contract ERC725 {
|
|||
event KeyRemoved(bytes32 indexed key, uint256 indexed purpose, uint256 indexed keyType);
|
||||
event ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
|
||||
event Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
|
||||
event ExecutionFailed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data);
|
||||
event Approved(uint256 indexed executionId, bool approved);
|
||||
|
||||
struct Key {
|
||||
uint256 purpose; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc.
|
||||
uint256[] purposes; //e.g., MANAGEMENT_KEY = 1, ACTION_KEY = 2, etc.
|
||||
uint256 keyType; // e.g. 1 = ECDSA, 2 = RSA, etc.
|
||||
bytes32 key;
|
||||
}
|
||||
|
||||
function getKey(bytes32 _key, uint256 _purpose) public view returns(uint256 purpose, uint256 keyType, bytes32 key);
|
||||
function getKeyPurpose(bytes32 _key) public view returns(uint256[] purpose);
|
||||
function getKeysByPurpose(uint256 _purpose) public view returns(bytes32[] keys);
|
||||
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success);
|
||||
function removeKey(bytes32 _key, uint256 _purpose) public returns (bool success);
|
||||
|
||||
function execute(address _to, uint256 _value, bytes _data) public returns (uint256 executionId);
|
||||
function approve(uint256 _id, bool _approve) public returns (bool success);
|
||||
function addKey(bytes32 _key, uint256 _purpose, uint256 _keyType) public returns (bool success);
|
||||
function removeKey(bytes32 _key, uint256 _purpose) public returns (bool success);
|
||||
function getKey(bytes32 _key) public view returns(uint256[] purposes, uint256 keyType, bytes32 key);
|
||||
function getKeyPurpose(bytes32 _key) public view returns(uint256[] purpose);
|
||||
function getKeysByPurpose(uint256 _purpose) public view returns(bytes32[] keys);
|
||||
function keyHasPurpose(bytes32 _key, uint256 purpose) public view returns(bool exists);
|
||||
}
|
|
@ -2,22 +2,22 @@ pragma solidity ^0.4.21;
|
|||
|
||||
contract ERC735 {
|
||||
|
||||
event ClaimRequested(bytes32 indexed claimRequestId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimAdded(bytes32 indexed claimId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimRemoved(bytes32 indexed claimId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimChanged(bytes32 indexed claimId, uint256 indexed claimType, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimRequested(bytes32 indexed claimRequestId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimAdded(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimRemoved(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
event ClaimChanged(bytes32 indexed claimId, uint256 indexed topic, uint256 scheme, address indexed issuer, bytes signature, bytes data, string uri);
|
||||
|
||||
struct Claim {
|
||||
uint256 claimType;
|
||||
uint256 topic;
|
||||
uint256 scheme;
|
||||
address issuer; // msg.sender
|
||||
bytes signature; // this.address + claimType + data
|
||||
bytes signature; // this.address + topic + data
|
||||
bytes data;
|
||||
string uri;
|
||||
}
|
||||
|
||||
function getClaim(bytes32 _claimId) public view returns(uint256 claimType, uint256 scheme, address issuer, bytes signature, bytes data, string uri);
|
||||
function getClaimIdsByType(uint256 _claimType) public view returns(bytes32[] claimIds);
|
||||
function addClaim(uint256 _claimType, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) public returns (bytes32 claimRequestId);
|
||||
function getClaim(bytes32 _claimId) public view returns(uint256 topic, uint256 scheme, address issuer, bytes signature, bytes data, string uri);
|
||||
function getClaimIdsByTopic(uint256 _topic) public view returns(bytes32[] claimIds);
|
||||
function addClaim(uint256 _topic, uint256 _scheme, address _issuer, bytes _signature, bytes _data, string _uri) public returns (bytes32 claimRequestId);
|
||||
function removeClaim(bytes32 _claimId) public returns (bool success);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -9,25 +9,49 @@ contract IdentityFactory is Factory {
|
|||
|
||||
event IdentityCreated(address instance);
|
||||
|
||||
function IdentityFactory(bytes _infohash)
|
||||
constructor()
|
||||
public
|
||||
Factory(new IdentityKernel())
|
||||
Factory(new IdentityKernel())
|
||||
{
|
||||
}
|
||||
|
||||
function createIdentity()
|
||||
external
|
||||
returns (address)
|
||||
{
|
||||
return createIdentity(msg.sender);
|
||||
{
|
||||
|
||||
bytes32[] memory initKeys = new bytes32[](2);
|
||||
uint256[] memory initPurposes = new uint256[](2);
|
||||
uint256[] memory initTypes = new uint256[](2);
|
||||
initKeys[0] = keccak256(msg.sender);
|
||||
initKeys[1] = initKeys[0];
|
||||
initPurposes[0] = 0;
|
||||
initPurposes[1] = 1;
|
||||
initTypes[0] = 0;
|
||||
initTypes[1] = 0;
|
||||
return createIdentity(
|
||||
initKeys,
|
||||
initPurposes,
|
||||
initTypes,
|
||||
1,
|
||||
1,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
function createIdentity(address _idOwner)
|
||||
function createIdentity(
|
||||
bytes32[] _keys,
|
||||
uint256[] _purposes,
|
||||
uint256[] _types,
|
||||
uint256 _managerThreshold,
|
||||
uint256 _actorThreshold,
|
||||
address _recoveryContract
|
||||
)
|
||||
public
|
||||
returns (address)
|
||||
{
|
||||
IdentityKernel instance = IdentityKernel(new DelayedUpdatableInstance(address(latestKernel)));
|
||||
instance.initIdentity(_idOwner);
|
||||
instance.initIdentity(_keys,_purposes,_types,_managerThreshold,_actorThreshold,_recoveryContract);
|
||||
emit IdentityCreated(address(instance));
|
||||
return instance;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,34 @@ import "./Identity.sol";
|
|||
|
||||
contract IdentityKernel is DelayedUpdatableInstanceStorage, Identity {
|
||||
|
||||
function initIdentity(address _caller) external {
|
||||
_constructIdentity(_caller);
|
||||
constructor()
|
||||
Identity(
|
||||
new bytes32[](0),
|
||||
new uint256[](0),
|
||||
new uint256[](0),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
public
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
function initIdentity(
|
||||
bytes32[] _keys,
|
||||
uint256[] _purposes,
|
||||
uint256[] _types,
|
||||
uint256 _managerThreshold,
|
||||
uint256 _actorThreshold,
|
||||
address _recoveryContract
|
||||
) external {
|
||||
_constructIdentity(
|
||||
_keys,
|
||||
_purposes,
|
||||
_types,
|
||||
_managerThreshold,
|
||||
_actorThreshold,
|
||||
_recoveryContract);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
|
||||
contract TestContract {
|
||||
|
@ -6,7 +6,7 @@ contract TestContract {
|
|||
event TestFunctionExecuted();
|
||||
|
||||
function test() public {
|
||||
TestFunctionExecuted();
|
||||
emit TestFunctionExecuted();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pragma solidity ^0.4.17;
|
||||
pragma solidity ^0.4.23;
|
||||
|
||||
import "../identity/IdentityKernel.sol";
|
||||
|
||||
|
@ -8,6 +8,6 @@ contract UpdatedIdentityKernel is IdentityKernel {
|
|||
event TestFunctionExecuted(uint256 minApprovalsByManagementKeys);
|
||||
|
||||
function test() public {
|
||||
TestFunctionExecuted(purposeThreshold[MANAGEMENT_KEY]);
|
||||
emit TestFunctionExecuted(purposeThreshold[MANAGEMENT_KEY]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
pragma solidity ^0.4.23;
|
||||
|
||||
import "./ERC20Token.sol";
|
||||
|
||||
contract ERC20Receiver {
|
||||
|
||||
event TokenDeposited(address indexed token, address indexed sender, uint256 amount);
|
||||
event TokenWithdrawn(address indexed token, address indexed sender, uint256 amount);
|
||||
|
||||
mapping (address => mapping(address => uint256)) tokenBalances;
|
||||
|
||||
constructor() public {
|
||||
|
||||
}
|
||||
|
||||
function depositToken(
|
||||
ERC20Token _token
|
||||
)
|
||||
external
|
||||
{
|
||||
_depositToken(
|
||||
msg.sender,
|
||||
_token,
|
||||
_token.allowance(
|
||||
msg.sender,
|
||||
address(this)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function withdrawToken(
|
||||
ERC20Token _token,
|
||||
uint256 _amount
|
||||
)
|
||||
external
|
||||
{
|
||||
_withdrawToken(msg.sender, _token, _amount);
|
||||
}
|
||||
|
||||
function depositToken(
|
||||
ERC20Token _token,
|
||||
uint256 _amount
|
||||
)
|
||||
external
|
||||
{
|
||||
require(_token.allowance(msg.sender, address(this)) >= _amount);
|
||||
_depositToken(msg.sender, _token, _amount);
|
||||
}
|
||||
|
||||
function tokenBalanceOf(
|
||||
ERC20Token _token,
|
||||
address _from
|
||||
)
|
||||
external
|
||||
view
|
||||
returns(uint256 fromTokenBalance)
|
||||
{
|
||||
return tokenBalances[address(_token)][_from];
|
||||
}
|
||||
|
||||
function _depositToken(
|
||||
address _from,
|
||||
ERC20Token _token,
|
||||
uint256 _amount
|
||||
)
|
||||
private
|
||||
{
|
||||
require(_amount > 0);
|
||||
if (_token.transferFrom(_from, address(this), _amount)) {
|
||||
tokenBalances[address(_token)][_from] += _amount;
|
||||
emit TokenDeposited(address(_token), _from, _amount);
|
||||
}
|
||||
}
|
||||
|
||||
function _withdrawToken(
|
||||
address _from,
|
||||
ERC20Token _token,
|
||||
uint256 _amount
|
||||
)
|
||||
private
|
||||
{
|
||||
require(_amount > 0);
|
||||
require(tokenBalances[address(_token)][_from] >= _amount);
|
||||
tokenBalances[address(_token)][_from] -= _amount;
|
||||
require(_token.transfer(_from, _amount));
|
||||
emit TokenWithdrawn(address(_token), _from, _amount);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -66,7 +66,7 @@ contract StandardToken is ERC20Token {
|
|||
function totalSupply()
|
||||
external
|
||||
view
|
||||
returns(uint256 supply)
|
||||
returns(uint256 currentTotalSupply)
|
||||
{
|
||||
return supply;
|
||||
}
|
||||
|
|
13
embark.json
13
embark.json
|
@ -1,10 +1,17 @@
|
|||
{
|
||||
"contracts": ["contracts/**"],
|
||||
"app": {
|
||||
"js/dapp.js": ["app/dapp.js"],
|
||||
"index.html": "app/index.html",
|
||||
"images/": ["app/images/**"]
|
||||
},
|
||||
"buildDir": "dist/",
|
||||
"config": "config/",
|
||||
"plugins": {
|
||||
},
|
||||
"versions": {
|
||||
"solc": "0.4.23"
|
||||
"web3": "1.0.0-beta",
|
||||
"solc": "0.4.23",
|
||||
"ipfs-api": "17.2.4"
|
||||
},
|
||||
"plugins": {
|
||||
}
|
||||
}
|
||||
|
|
14
package.json
14
package.json
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "status-contracts",
|
||||
"version": "1.0.0",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"solidity-coverage": "./node_modules/.bin/solidity-coverage",
|
||||
"test": "embark test"
|
||||
|
@ -15,13 +16,10 @@
|
|||
"url": "https://github.com/status-im/contracts/issues"
|
||||
},
|
||||
"homepage": "https://github.com/status-im/contracts#readme",
|
||||
"devDependencies": {
|
||||
"solidity-coverage": "^0.5.0",
|
||||
"elliptic": "^6.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"embark": "^2.7.0",
|
||||
"elliptic-curve": "^0.1.0",
|
||||
"ethereumjs-util": "^5.1.5"
|
||||
"web3-eth-abi": "^1.0.0-beta.34",
|
||||
"react": "^16.3.2",
|
||||
"react-bootstrap": "^0.32.1",
|
||||
"react-dom": "^16.3.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
describe("ERC20Token", async function() {
|
||||
this.timeout(0);
|
||||
var ERC20Token;
|
||||
var accountsArr;
|
||||
before(function(done) {
|
||||
this.timeout(0);
|
||||
var contractsConfig = {
|
||||
"TestToken": { },
|
||||
"ERC20Receiver": { }
|
||||
};
|
||||
EmbarkSpec.deployAll(contractsConfig, async function(accounts) {
|
||||
ERC20Token = TestToken;
|
||||
accountsArr = accounts;
|
||||
for(i=0;i<accountsArr.length;i++){
|
||||
await ERC20Token.methods.mint(7 * 10 ^ 18).send({from: accountsArr[i]})
|
||||
}
|
||||
done()
|
||||
});
|
||||
});
|
||||
|
||||
it("should transfer 1 token", async function() {
|
||||
let initialBalance0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
|
||||
let initialBalance1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
|
||||
await ERC20Token.methods.transfer(accountsArr[1],1).send({from: accountsArr[0]});
|
||||
let result0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
|
||||
let result1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
|
||||
|
||||
assert.equal(result0, +initialBalance0-1);
|
||||
assert.equal(result1, +initialBalance1+1);
|
||||
});
|
||||
|
||||
it("should set approved amount", async function() {
|
||||
await ERC20Token.methods.approve(accountsArr[2],10000000).send({from: accountsArr[0]});
|
||||
let result = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
|
||||
assert.equal(result, 10000000);
|
||||
});
|
||||
|
||||
it("should consume allowance amount", async function() {
|
||||
let initialAllowance = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
|
||||
await ERC20Token.methods.transferFrom(accountsArr[0], accountsArr[0],1).send({from: accountsArr[2]});
|
||||
let result = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
|
||||
|
||||
assert.equal(result, +initialAllowance-1);
|
||||
});
|
||||
|
||||
it("should transfer approved amount", async function() {
|
||||
let initialBalance0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
|
||||
let initialBalance1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
|
||||
await ERC20Token.methods.transferFrom(accountsArr[0], accountsArr[1],1).send({from: accountsArr[2]});
|
||||
let result0 = await ERC20Token.methods.balanceOf(accountsArr[0]).call();
|
||||
let result1 = await ERC20Token.methods.balanceOf(accountsArr[1]).call();
|
||||
|
||||
assert.equal(result0, +initialBalance0-1);
|
||||
assert.equal(result1, +initialBalance1+1);
|
||||
});
|
||||
|
||||
|
||||
it("should unset approved amount", async function() {
|
||||
await ERC20Token.methods.approve(accountsArr[2],0).send({from: accountsArr[0]});
|
||||
let result = await ERC20Token.methods.allowance(accountsArr[0], accountsArr[2]).call();
|
||||
assert.equal(result, 0);
|
||||
});
|
||||
|
||||
it("should deposit approved amount to contract ERC20Receiver", async function() {
|
||||
await ERC20Token.methods.approve(ERC20Receiver.address,10).send({from: accountsArr[0]});
|
||||
await ERC20Receiver.methods.depositToken(ERC20Token.address).send({from: accountsArr[0]});
|
||||
let result = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accountsArr[0]).call();
|
||||
assert.equal(result, 10, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accountsArr[0]+") wrong");
|
||||
});
|
||||
|
||||
it("should witdraw approved amount from contract ERC20Receiver", async function() {
|
||||
let tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accountsArr[0]).call();
|
||||
await ERC20Receiver.methods.withdrawToken(ERC20Token.address, tokenBalance).send({from: accountsArr[0]});
|
||||
tokenBalance = await ERC20Receiver.methods.tokenBalanceOf(ERC20Token.address, accountsArr[0]).call();
|
||||
assert.equal(tokenBalance, 0, "ERC20Receiver.tokenBalanceOf("+ERC20Token.address+","+accountsArr[0]+") wrong");
|
||||
});
|
||||
|
||||
//TODO: include checks for expected events fired
|
||||
|
||||
|
||||
});
|
|
@ -1,11 +1,3 @@
|
|||
const assert = require('assert');
|
||||
const Embark = require('embark');
|
||||
let EmbarkSpec = Embark.initTests();
|
||||
let web3 = EmbarkSpec.web3;
|
||||
|
||||
const identityJson = require('../dist/contracts/Identity.json');
|
||||
const updatedIdentityKernelJson = require('../dist/contracts/UpdatedIdentityKernel.json');
|
||||
|
||||
const TestUtils = require("../utils/testUtils.js")
|
||||
const idUtils = require("../utils/identityUtils.js")
|
||||
|
||||
|
|
167
test/identity.js
167
test/identity.js
|
@ -1,8 +1,4 @@
|
|||
|
||||
const assert = require('assert');
|
||||
const Embark = require('embark');
|
||||
let EmbarkSpec = Embark.initTests();
|
||||
let web3 = EmbarkSpec.web3;
|
||||
const TestUtils = require("../utils/testUtils.js");
|
||||
const idUtils = require('../utils/identityUtils.js');
|
||||
|
||||
|
@ -11,14 +7,15 @@ describe("Identity", function() {
|
|||
|
||||
let accounts;
|
||||
|
||||
beforeEach( function(done) {
|
||||
before( function(done) {
|
||||
this.timeout(0);
|
||||
|
||||
EmbarkSpec = Embark.initTests();
|
||||
web3 = EmbarkSpec.web3;
|
||||
|
||||
EmbarkSpec.deployAll({
|
||||
"Identity": {},
|
||||
"Identity": {
|
||||
args: [
|
||||
[],[],[],0,0,0
|
||||
]
|
||||
},
|
||||
"TestContract": {}
|
||||
}, (_accounts) => {
|
||||
accounts = _accounts;
|
||||
|
@ -28,27 +25,31 @@ describe("Identity", function() {
|
|||
|
||||
describe("Identity()", () => {
|
||||
it("initialize with msg.sender as management key", async () => {
|
||||
var result = await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[0]), idUtils.purposes.MANAGEMENT).call()
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])).call(),
|
||||
idUtils.purposes.MANAGEMENT,
|
||||
Identity.address + ".getKeyPurpose("+accounts[0]+") is not MANAGEMENT_KEY");
|
||||
|
||||
result,
|
||||
true,
|
||||
Identity.address + ".keyHasPurpose("+web3.utils.soliditySha3(accounts[0])+","+idUtils.purposes.MANAGEMENT+") is not MANAGEMENT_KEY");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe("addKey(address _key, uint256 _type)", () => {
|
||||
it("MANAGEMENT_KEY add a new address as ACTION_KEY", async () => {
|
||||
assert.equal(
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION).call(),
|
||||
false);
|
||||
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS)
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS)
|
||||
).send({from: accounts[0]});
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.ACTION,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not ACTION_KEY");
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION).call(),
|
||||
true);
|
||||
});
|
||||
|
||||
it("should not add key by non manager", async () => {
|
||||
|
@ -56,7 +57,7 @@ describe("Identity", function() {
|
|||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[2]});
|
||||
assert.fail('should have reverted before');
|
||||
} catch(error) {
|
||||
|
@ -64,9 +65,9 @@ describe("Identity", function() {
|
|||
}
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.NONE,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not correct");
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT).call(),
|
||||
false)
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
@ -74,14 +75,14 @@ describe("Identity", function() {
|
|||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[2], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[2]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
try {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[2]});
|
||||
assert.fail('should have reverted before');
|
||||
} catch(error) {
|
||||
|
@ -89,20 +90,19 @@ describe("Identity", function() {
|
|||
}
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.NONE,
|
||||
Identity.address+".getKeyType("+accounts[1]+") is not correct");
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT).call(),
|
||||
false);
|
||||
});
|
||||
|
||||
it("fire KeyAdded(address indexed key, uint256 indexed type)", async () => {
|
||||
xit("fire KeyAdded(address indexed key, uint256 indexed type)", async () => {
|
||||
let receipt = await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
const keyAdded = TestUtils.eventValues(receipt, "KeyAdded");
|
||||
assert(keyAdded.key, TestUtils.addressToBytes32(accounts[1]), "Key is not correct")
|
||||
assert(keyAdded.key, web3.utils.soliditySha3(accounts[1]), "Key is not correct")
|
||||
assert(keyAdded.keyType, idUtils.types.ADDRESS, "Type is not correct")
|
||||
});
|
||||
});
|
||||
|
@ -113,33 +113,33 @@ describe("Identity", function() {
|
|||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[5]), idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.removeKey(accounts[1], idUtils.purposes.MANAGEMENT))
|
||||
idUtils.encode.removeKey(web3.utils.soliditySha3(accounts[5]), idUtils.purposes.MANAGEMENT))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.NONE,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not 0")
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[5]), idUtils.purposes.MANAGEMENT).call(),
|
||||
false,
|
||||
Identity.address+".keyHasPurpose("+web3.utils.soliditySha3(accounts[5])+","+idUtils.purposes.MANAGEMENT+") is not false")
|
||||
});
|
||||
|
||||
it("other key should not remove a key", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
try {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.removeKey(accounts[1], idUtils.purposes.MANAGEMENT))
|
||||
idUtils.encode.removeKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT))
|
||||
.send({from: accounts[2]});
|
||||
assert.fail('should have reverted before');
|
||||
} catch(error) {
|
||||
|
@ -147,29 +147,29 @@ describe("Identity", function() {
|
|||
}
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.MANAGEMENT,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not 0")
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.MANAGEMENT).call(),
|
||||
true,
|
||||
Identity.address+".keyHasPurpose("+accounts[1]+","+idUtils.purposes.MANAGEMENT+") is not true")
|
||||
});
|
||||
|
||||
it("actor key should not remove key", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[2], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[2]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
try {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.removeKey(accounts[1], idUtils.purposes.ACTION))
|
||||
idUtils.encode.removeKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION))
|
||||
.send({from: accounts[2]});
|
||||
|
||||
assert.fail('should have reverted before');
|
||||
|
@ -178,86 +178,67 @@ describe("Identity", function() {
|
|||
}
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.ACTION,
|
||||
Identity.address+".getKeyType("+accounts[1]+") is not 0")
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION).call(),
|
||||
true,
|
||||
Identity.address+".keyHasPurpose("+accounts[1]+","+idUtils.purposes.ACTION+") is not true")
|
||||
});
|
||||
|
||||
it("MANAGEMENT_KEY should not remove itself MANAGEMENT_KEY when there is no other MANAGEMENT_KEY", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.removeKey(accounts[0], idUtils.purposes.MANAGEMENT))
|
||||
idUtils.encode.removeKey(web3.utils.soliditySha3(accounts[0]), idUtils.purposes.MANAGEMENT))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])).call(),
|
||||
idUtils.purposes.MANAGEMENT,
|
||||
Identity.address+".getKeyType("+accounts[0]+") is not 1")
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[0]), idUtils.purposes.MANAGEMENT).call(),
|
||||
true,
|
||||
Identity.address+".keyHasPurpose("+web3.utils.soliditySha3(accounts[0])+") is not true")
|
||||
});
|
||||
|
||||
it("fire KeyRemoved(address indexed key, uint256 indexed type)", async () => {
|
||||
xit("fire KeyRemoved(address indexed key, uint256 indexed type)", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
let receipt = await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.removeKey(accounts[1], idUtils.purposes.ACTION))
|
||||
idUtils.encode.removeKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
const keyRemoved = TestUtils.eventValues(receipt, "KeyRemoved");
|
||||
assert(keyRemoved.key, TestUtils.addressToBytes32(accounts[1]), "Key is not correct");
|
||||
assert(keyRemoved.key, web3.utils.soliditySha3(accounts[1]), "Key is not correct");
|
||||
assert(keyRemoved.keyType, idUtils.types.ADDRESS, "Type is not correct");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("getKeyPurpose(address _key)", () => {
|
||||
|
||||
it("should start only with initializer as only key", async () => {
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[0])).call(),
|
||||
idUtils.purposes.MANAGEMENT,
|
||||
Identity.address+".getKeyPurpose("+accounts[0]+") is not correct")
|
||||
describe("keyHasPurpose(address _key)", () => {
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.NONE,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not correct")
|
||||
});
|
||||
|
||||
it("should get type 2 after addKey type 2", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.ACTION,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not correct")
|
||||
});
|
||||
|
||||
it("should get type 3 after addKey type 3", async () => {
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.CLAIM_SIGNER).call(),
|
||||
false,
|
||||
Identity.address+".keyHasPurpose("+accounts[1]+","+idUtils.purposes.CLAIM_SIGNER+") is not false")
|
||||
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.CLAIM_SIGNER, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.CLAIM_SIGNER, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
assert.equal(
|
||||
await Identity.methods.getKeyPurpose(TestUtils.addressToBytes32(accounts[1])).call(),
|
||||
idUtils.purposes.CLAIM_SIGNER,
|
||||
Identity.address+".getKeyPurpose("+accounts[1]+") is not correct")
|
||||
await Identity.methods.keyHasPurpose(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.CLAIM_SIGNER).call(),
|
||||
true,
|
||||
Identity.address+".keyHasPurpose("+accounts[1]+","+idUtils.purposes.CLAIM_SIGNER+") is not true")
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
/*
|
||||
describe("getKeysByType(uint256 _type)", () => {
|
||||
|
||||
|
@ -278,7 +259,7 @@ describe("Identity", function() {
|
|||
describe("execute(address _to, uint256 _value, bytes _data)", () => {
|
||||
let functionPayload;
|
||||
|
||||
it("Identity should receive ether", async() => {
|
||||
xit("Identity should receive ether", async() => {
|
||||
|
||||
const amountToSend = web3.utils.toWei('0.05', "ether");
|
||||
|
||||
|
@ -295,7 +276,7 @@ describe("Identity", function() {
|
|||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
|
||||
|
@ -346,11 +327,11 @@ describe("Identity", function() {
|
|||
});
|
||||
|
||||
|
||||
it("ACTION_KEY should send ether from contract", async () => {
|
||||
xit("ACTION_KEY should send ether from contract", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
// Adding funds to contract
|
||||
|
@ -374,11 +355,11 @@ describe("Identity", function() {
|
|||
assert(web3.utils.toBN(a2Balance1).toString(), web3.utils.toBN(a2Balance0).add(web3.utils.toBN(amountToSend)).toString(), accounts[2] + " did not receive ether");
|
||||
});
|
||||
|
||||
it("fire ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)", async () => {
|
||||
xit("fire ExecutionRequested(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
let receipt = await Identity.methods.execute(
|
||||
|
@ -393,11 +374,11 @@ describe("Identity", function() {
|
|||
assert(executionRequested.data, functionPayload, "Data is not correct");
|
||||
});
|
||||
|
||||
it("fire Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)", async () => {
|
||||
xit("fire Executed(uint256 indexed executionId, address indexed to, uint256 indexed value, bytes data)", async () => {
|
||||
await Identity.methods.execute(
|
||||
Identity.address,
|
||||
0,
|
||||
idUtils.encode.addKey(accounts[1], idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
idUtils.encode.addKey(web3.utils.soliditySha3(accounts[1]), idUtils.purposes.ACTION, idUtils.types.ADDRESS))
|
||||
.send({from: accounts[0]});
|
||||
|
||||
let receipt = await Identity.methods.execute(
|
||||
|
@ -447,7 +428,7 @@ describe("Identity", function() {
|
|||
|
||||
});
|
||||
|
||||
it("fire Approved(uint256 indexed executionId, bool approved)", async () => {
|
||||
xit("fire Approved(uint256 indexed executionId, bool approved)", async () => {
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
describe("TestToken", async function() {
|
||||
this.timeout(0);
|
||||
var accountsArr;
|
||||
|
||||
before(function(done) {
|
||||
this.timeout(0);
|
||||
var contractsConfig = {
|
||||
"TestToken": {
|
||||
}
|
||||
};
|
||||
EmbarkSpec.deployAll(contractsConfig, async function(accounts) {
|
||||
accountsArr = accounts
|
||||
for(i=0;i<accountsArr.length;i++) {
|
||||
await TestToken.methods.mint(7 * 10 ^ 18).send({from: accountsArr[i]})
|
||||
}
|
||||
done()
|
||||
});
|
||||
});
|
||||
|
||||
it("should increase totalSupply in mint", async function() {
|
||||
let initialSupply = await TestToken.methods.totalSupply().call();
|
||||
await TestToken.methods.mint(100).send({from: accountsArr[0]});
|
||||
let result = await TestToken.methods.totalSupply().call();
|
||||
assert.equal(result, +initialSupply+100);
|
||||
});
|
||||
|
||||
it("should increase accountBalance in mint", async function() {
|
||||
let initialBalance = await TestToken.methods.balanceOf(accountsArr[0]).call();
|
||||
await TestToken.methods.mint(100).send({from: accountsArr[0]});
|
||||
let result = await TestToken.methods.balanceOf(accountsArr[0]).call();
|
||||
assert.equal(result, +initialBalance+100);
|
||||
});
|
||||
|
||||
});
|
|
@ -85,8 +85,6 @@ var callbackToResolve = function (resolve, reject) {
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
exports.promisify = (func) =>
|
||||
(...args) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -95,3 +93,105 @@ exports.promisify = (func) =>
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
// This has been tested with the real Ethereum network and Testrpc.
|
||||
// Copied and edited from: https://gist.github.com/xavierlepretre/d5583222fde52ddfbc58b7cfa0d2d0a9
|
||||
exports.assertReverts = (contractMethodCall, maxGasAvailable) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(contractMethodCall())
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
.then(tx => {
|
||||
assert.equal(tx.receipt.gasUsed, maxGasAvailable, "tx successful, the max gas available was not consumed")
|
||||
})
|
||||
.catch(error => {
|
||||
if ((error + "").indexOf("invalid opcode") < 0 && (error + "").indexOf("out of gas") < 0) {
|
||||
// Checks if the error is from TestRpc. If it is then ignore it.
|
||||
// Otherwise relay/throw the error produced by the above assertion.
|
||||
// Note that no error is thrown when using a real Ethereum network AND the assertion above is true.
|
||||
throw error
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exports.listenForEvent = event => new Promise((resolve, reject) => {
|
||||
event({}, (error, response) => {
|
||||
if (!error) {
|
||||
resolve(response.args)
|
||||
} else {
|
||||
reject(error)
|
||||
}
|
||||
event.stopWatching()
|
||||
})
|
||||
});
|
||||
|
||||
exports.eventValues = (receipt, eventName) => {
|
||||
if(receipt.events[eventName])
|
||||
return receipt.events[eventName].returnValues;
|
||||
}
|
||||
|
||||
exports.addressToBytes32 = (address) => {
|
||||
const stringed = "0000000000000000000000000000000000000000000000000000000000000000" + address.slice(2);
|
||||
return "0x" + stringed.substring(stringed.length - 64, stringed.length);
|
||||
}
|
||||
|
||||
|
||||
// OpenZeppelin's expectThrow helper -
|
||||
// Source: https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
|
||||
exports.expectThrow = async promise => {
|
||||
try {
|
||||
await promise;
|
||||
} catch (error) {
|
||||
// TODO: Check jump destination to destinguish between a throw
|
||||
// and an actual invalid jump.
|
||||
const invalidOpcode = error.message.search('invalid opcode') >= 0;
|
||||
// TODO: When we contract A calls contract B, and B throws, instead
|
||||
// of an 'invalid jump', we get an 'out of gas' error. How do
|
||||
// we distinguish this from an actual out of gas event? (The
|
||||
// testrpc log actually show an 'invalid jump' event.)
|
||||
const outOfGas = error.message.search('out of gas') >= 0;
|
||||
const revert = error.message.search('revert') >= 0;
|
||||
assert(
|
||||
invalidOpcode || outOfGas || revert,
|
||||
'Expected throw, got \'' + error + '\' instead',
|
||||
);
|
||||
return;
|
||||
}
|
||||
assert.fail('Expected throw not received');
|
||||
};
|
||||
|
||||
exports.assertJump = (error) => {
|
||||
assert(error.message.search('revert') > -1, 'Revert should happen');
|
||||
}
|
||||
|
||||
var callbackToResolve = function (resolve, reject) {
|
||||
return function (error, value) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.promisify = (func) =>
|
||||
(...args) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = (err, data) => err ? reject(err) : resolve(data);
|
||||
func.apply(this, [...args, callback]);
|
||||
});
|
||||
}
|
||||
|
||||
exports.zeroAddress = '0x0000000000000000000000000000000000000000';
|
||||
exports.zeroBytes32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
||||
exports.ensureException = function(error) {
|
||||
assert(isException(error), error.toString());
|
||||
};
|
||||
|
||||
function isException(error) {
|
||||
let strError = error.toString();
|
||||
return strError.includes('invalid opcode') || strError.includes('invalid JUMP') || strError.includes('revert');
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue