Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

contracts: corrections to nonces and redeem comment #1

Merged
merged 4 commits into from
Nov 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# OSX
.DS_Store

# Vagrant
.vagrant/
ubuntu-xenial-16.04-cloudimg-console.log

# don't commit contract binaries in protocol
# we do commit the contract binaries in platform
contracts/bin/
67 changes: 67 additions & 0 deletions Vagrantfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.

# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "ubuntu/xenial64"

# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# config.vm.network "forwarded_port", guest: 80, host: 8080

# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"

# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"

# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"

# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"

# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.

# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
config.vm.provision :shell, path: "dev/local-poa-geth.sh"
end
51 changes: 28 additions & 23 deletions contracts/Staking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pragma solidity ^0.4.17;
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// ----------------------------------------------------------------------------
// Staking
//
Expand Down Expand Up @@ -43,8 +43,7 @@ contract Staking is OpsManaged, StakingData {
eip20Token = _eip20Token;
}

// TBD: move to a parent contract because this is identical to `hashIntent` in Staking?
function hashIntent(
function hashMintingIntent(
bytes32 _uuid,
address _account,
uint256 _accountNonce,
Expand All @@ -58,6 +57,17 @@ contract Staking is OpsManaged, StakingData {
return keccak256(_uuid, _account, _accountNonce, _amountST, _amountUT, _escrowUnlockHeight);
}

function hashUnstakingIntent(
bytes32 _uuid,
address _account,
uint256 _accountNonce,
uint256 _amountUT,
uint256 _escrowUnlockHeight
)
public pure returns (bytes32) {
return keccak256(_uuid, _account, _accountNonce, _amountUT, _escrowUnlockHeight);
}

// @dev `_chainId` should be blank for MVU
// @dev `_stakingAccount` is optional
function registerUtilityToken(
Expand All @@ -68,7 +78,7 @@ contract Staking is OpsManaged, StakingData {
bytes32 _chainId,
address _stakingAccount
)
public onlyAdmin returns (bool, bytes32) {
public onlyAdmin returns(bytes32) {
require(bytes(_name).length > 0);
require(bytes(_symbol).length > 0);
require(_decimals > 0);
Expand All @@ -91,11 +101,11 @@ contract Staking is OpsManaged, StakingData {

UtilityTokenRegistered(uuid, _symbol, _name, _decimals, _conversionRate, _chainId, _stakingAccount);

return (true, uuid);
return uuid;
}
// 2 step like ownership --> Yes
// If this is 0, it cannot be set to non-0

// TODO: 2 step change
// Require that if this is 0, it cannot be set to non-0
function setUtilityTokenStakingAccount(bytes32 _uuid, address _newStakingAccount) public returns (bool) {
require(_uuid != "");
require(utilityTokens[_uuid].conversionRate > 0);
Expand All @@ -104,7 +114,7 @@ contract Staking is OpsManaged, StakingData {
// TODO;
}

function stake(bytes32 _uuid, uint256 _amountST) external returns (bool, uint256) {
function stake(bytes32 _uuid, uint256 _amountST) external returns (uint256) {
require(_uuid != "");
require(utilityTokens[_uuid].conversionRate > 0);
require(_amountST > 0);
Expand All @@ -115,8 +125,9 @@ contract Staking is OpsManaged, StakingData {
require(eip20Token.transferFrom(msg.sender, address(this), _amountST));

uint256 amountUT = _amountST.mul(utilityToken.conversionRate);
uint256 escrowUnlockHeight = block.number + BLOCKS_TO_WAIT;
bytes32 mintingIntentHash = hashIntent(
uint256 escrowUnlockHeight = block.number + BLOCKS_TO_WAIT_LONG;
nonces[msg.sender]++;
bytes32 mintingIntentHash = hashMintingIntent(
_uuid,
msg.sender,
nonces[msg.sender],
Expand All @@ -142,16 +153,13 @@ contract Staking is OpsManaged, StakingData {
mintingIntentHash
);

nonces[msg.sender]++;

return (true, amountUT);
return amountUT;
}

// TODO: Come back to this
// when calling hashIntent, make sure the beneficiary is passed in as _staker
// when calling hashMintingIntent, make sure the beneficiary is passed in as _staker
// if _uuid == a branded token, require(msg.sender == adminAddress) && require(_beneficiary == utilityTokens[_uuid].stakingAccount)
// requires(eip20Token.transferFrom(_beneficiary, this, _amount))
// Calls hashIntent
// Calls hashMintingIntent
// Adds Stake to stakes
// Emits event: MintingIntentDeclared
function stakeFor(address _beneficiary, bytes32 _uuid, uint256 _amountST) external returns (bool, uint256) {
Expand All @@ -164,7 +172,6 @@ contract Staking is OpsManaged, StakingData {
}

// @dev Checks msg.sender for purposes of MVU
// TBD: don't delete Stake after processing?
function processStaking(bytes32 _uuid, bytes32 _mintingIntentHash) external returns (bool) {
require(_uuid != "");
require(utilityTokens[_uuid].conversionRate > 0);
Expand All @@ -189,20 +196,19 @@ contract Staking is OpsManaged, StakingData {
uint256 _amountUT,
uint256 _escrowUnlockHeight,
bytes32 _unstakingIntentHash
) external returns (bool) {
) external onlyAdmin returns (bool) {
require(_uuid != "");
require(utilityTokens[_uuid].conversionRate > 0);
require(utilityTokens[_uuid].conversionRate > 0);
require(nonces[_unstaker] < _unstakerNonce);
require(_amountST > 0);
require(_amountUT > 0);
require(_escrowUnlockHeight > 0);
require(_unstakingIntentHash != "");

bytes32 unstakingIntentHash = hashIntent(
bytes32 unstakingIntentHash = hashUnstakingIntent(
_uuid,
_unstaker,
nonces[_unstaker],
_amountST,
_amountUT,
_escrowUnlockHeight
);
Expand All @@ -220,7 +226,6 @@ contract Staking is OpsManaged, StakingData {
return true;
}

// TBD: don't delete Unstake after processing?
function processUnstaking(bytes32 _uuid, bytes32 _unstakingIntentHash) public returns (bool) {
require(_uuid != "");
require(utilityTokens[_uuid].conversionRate > 0);
Expand Down
4 changes: 3 additions & 1 deletion contracts/StakingData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ contract StakingData {
EIP20Interface public eip20Token;

// ~2 weeks, assuming ~15s per block
uint256 public constant BLOCKS_TO_WAIT = 80667;
uint256 public constant BLOCKS_TO_WAIT_LONG = 80667;
// ~1hour, assuming ~15s per block
uint256 public constant BLOCKS_TO_WAIT_SHORT = 240;

// [uuid == H(utility token name, chainId)]
mapping(bytes32 => UtilityToken) public utilityTokens;
Expand Down
53 changes: 31 additions & 22 deletions contracts/UtilityToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pragma solidity ^0.4.17;
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//
// ----------------------------------------------------------------------------
// Utility Token
//
Expand All @@ -32,7 +32,7 @@ import "./UtilityTokenData.sol";
contract UtilityToken is EIP20Token, UtilityTokenData {
using SafeMath for uint256;

event UnstakingIntentDeclared(bytes32 indexed _uuid, address indexed _unstaker, uint256 _unstakerNonce, uint256 _amountST, uint256 _amountUT, uint256 _escrowUnlockHeight, bytes32 _unstakingIntentHash /* redundant for abundance of clarity for MVU */);
event UnstakingIntentDeclared(bytes32 indexed _uuid, address indexed _unstaker, uint256 _unstakerNonce, uint256 _amountUT, uint256 _escrowUnlockHeight, bytes32 _unstakingIntentHash /* redundant for abundance of clarity for MVU */);
event Redeemed(bytes32 indexed _uuid, address indexed _account, uint256 _amount, uint256 _balance, uint256 _totalSupply);
event MintingIntentConfirmed(bytes32 indexed _uuid, bytes32 _mintingIntentHash);
event Minted(bytes32 indexed _uuid, address indexed _account, uint256 _amount, uint256 _balance, uint256 _totalSupply);
Expand All @@ -48,8 +48,8 @@ contract UtilityToken is EIP20Token, UtilityTokenData {
uuid = keccak256(_name, _chainId);
}

// TBD: move to a parent contract because this is identical to `hashIntent` in Staking?
function hashIntent(
// TBD: move to a parent contract because this is identical to `hashMintingIntent` in Staking?
function hashMintingIntent(
bytes32 _uuid,
address _account,
uint256 _accountNonce,
Expand All @@ -61,26 +61,39 @@ contract UtilityToken is EIP20Token, UtilityTokenData {
return keccak256(_uuid, _account, _accountNonce, _amountST, _amountUT, _escrowUnlockHeight);
}

function hashUnstakingIntent(
bytes32 _uuid,
address _account,
uint256 _accountNonce,
uint256 _amountUT,
uint256 _escrowUnlockHeight
)
public pure returns (bytes32) {
return keccak256(_uuid, _account, _accountNonce, _amountUT, _escrowUnlockHeight);
}

// @dev There's no need for msg.sender to approve this contract to transfer
// because calling `transfer` from `redeem` has the same msg.sender
function redeem(uint256 _amountUT) public returns (bool, uint256) {
// TODO redeem needs user nonce from staking contract as parameter
// and must be strictly greater than stored nonce in UtilityToken
function redeem(uint256 _amountUT) public returns (bool) {
require(_amountUT > 0);
require(transfer(address(this), _amountUT));

uint256 amountST = _amountUT.div(conversionRate);
uint256 escrowUnlockHeight = block.number + BLOCKS_TO_WAIT;
bytes32 unstakingIntentHash = hashIntent(
uint256 escrowUnlockHeight = block.number + BLOCKS_TO_WAIT_LONG;
bytes32 unstakingIntentHash = hashUnstakingIntent(
uuid,
msg.sender,
nonces[msg.sender],
amountST,
_amountUT,
escrowUnlockHeight
);

nonces[msg.sender]++;

redemptions[unstakingIntentHash] = Redemption({
redeemer: msg.sender,
amountUT: _amountUT,
amountST: amountST,
escrowUnlockHeight: escrowUnlockHeight
});

Expand All @@ -89,26 +102,22 @@ contract UtilityToken is EIP20Token, UtilityTokenData {
msg.sender,
nonces[msg.sender],
_amountUT,
amountST,
escrowUnlockHeight,
unstakingIntentHash
);

nonces[msg.sender]++;

return (true, amountST);
return (true);
}

// TBD: don't delete Redemption after processing?
function processRedepmtion(bytes32 _unstakingIntentHash) public returns (bool) {
require(_unstakingIntentHash != "");
require(redemptions[_unstakingIntentHash].redeemer == msg.sender);

Redemption storage redemption = redemptions[_unstakingIntentHash];
tokenTotalSupply = tokenTotalSupply.sub(redemption.amountST);
balances[address(this)] = balances[address(this)].sub(redemption.amountST);
tokenTotalSupply = tokenTotalSupply.sub(redemption.amountUT);
balances[address(this)] = balances[address(this)].sub(redemption.amountUT);

Redeemed(uuid, redemption.redeemer, redemption.amountST, balances[redemption.redeemer], tokenTotalSupply);
Redeemed(uuid, redemption.redeemer, redemption.amountUT, balances[redemption.redeemer], tokenTotalSupply);

delete redemptions[_unstakingIntentHash];

Expand All @@ -131,10 +140,12 @@ contract UtilityToken is EIP20Token, UtilityTokenData {
require(_escrowUnlockHeight > 0);
require(_mintingIntentHash != "");

bytes32 mintingIntentHash = hashIntent(
nonces[_minter] = _minterNonce;

bytes32 mintingIntentHash = hashMintingIntent(
_uuid,
_minter,
nonces[_minter],
_minterNonce,
_amountST,
_amountUT,
_escrowUnlockHeight
Expand All @@ -146,14 +157,12 @@ contract UtilityToken is EIP20Token, UtilityTokenData {
minter: _minter,
amount: _amountUT
});
nonces[_minter]++;

MintingIntentConfirmed(_uuid, mintingIntentHash);

return true;
}

// TBD: don't delete Mint after processing?
function processMinting(bytes32 _mintingIntentHash) external returns (bool) {
require(_mintingIntentHash != "");

Expand Down
5 changes: 3 additions & 2 deletions contracts/UtilityTokenData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ contract UtilityTokenData {
bytes32 public uuid;

// ~2 weeks, assuming ~15s per block
uint256 public constant BLOCKS_TO_WAIT = 80667;
uint256 public constant BLOCKS_TO_WAIT_LONG = 80667;
// ~1hour, assuming ~15s per block
uint256 public constant BLOCKS_TO_WAIT_SHORT = 240;

// [staker address]
mapping(address => uint) nonces;
Expand All @@ -48,7 +50,6 @@ contract UtilityTokenData {
struct Redemption {
address redeemer;
uint256 amountUT;
uint256 amountST;
uint256 escrowUnlockHeight;
}
}
Loading