diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..89c66e4 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 123ae94..994137b 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ build/Release # Dependency directory # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git node_modules +build \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3b66410 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "git.ignoreLimitWarning": true +} \ No newline at end of file diff --git a/contracts/.DS_Store b/contracts/.DS_Store new file mode 100644 index 0000000..1ea63f9 Binary files /dev/null and b/contracts/.DS_Store differ diff --git a/contracts/AttestStorage.sol b/contracts/AttestStorage.sol new file mode 100644 index 0000000..8d41465 --- /dev/null +++ b/contracts/AttestStorage.sol @@ -0,0 +1,108 @@ +pragma solidity ^0.4.19; +contract Ownable { + address public owner; + + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + function Ownable() { + owner = msg.sender; + } + + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + + /** + * @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) onlyOwner public { + require(newOwner != address(0)); + OwnershipTransferred(owner, newOwner); + owner = newOwner; + } + +} +contract AttestStorage is Ownable { + /** + The struct for attestations,claim etc... + */ + uint256 counter=0; + struct claimStructure { + string claim; + uint256 attest_level; + bool active; + } + struct attestationStructure { + string data; + string opposite_party_id; + uint256 attest_level; + bool active; + } + //mapping for user_id to ref id to struct detail + mapping(string=>mapping(string=>claimStructure)) claims; + //mapping for attestor id to user id to detail + mapping(string=>mapping(uint256=>attestationStructure)) attestations; + mapping(string=>uint256) attest_counter; + //mapping to allow access to only some addresses + mapping(address => bool) Access_allowed; + //to check that the request is actually coming from the vanity contract + modifier checkOwner(address _add) { + require(Access_allowed[_add]==true); + _; + } + //to set the contract address + function allowAccess(address newAddr) onlyOwner public { + Access_allowed[newAddr]=true; + } + + //function update claim by the user + function setClaimMapping(string uid,string ref_id,string _claim) checkOwner(msg.sender) public { + claims[uid][ref_id]=claimStructure(_claim,0,true); + } + //function to get current count for a refernce + function getCounter(string ref_id) public view returns(uint256) { + return attest_counter[ref_id]; + } + //function to set attesting mapping + function setAttestingsMapping(string uid1,string uid2,string ref_id,uint256 _level,uint256 count) checkOwner(msg.sender) public { + attestations[ref_id][count]=attestationStructure(claims[uid1][ref_id].claim,uid2,_level,true); + } + //function to set attest_counter mapping + function setAttestCounterMapping(string ref_id,uint256 count) checkOwner(msg.sender) public { + attest_counter[ref_id]=count; + } + //get the details through the pagination function + function getPaginationResults(uint256 index,string ref_id) public view returns(string,string,uint256,bool) { + require(keccak256(attestations[ref_id][index].opposite_party_id)!=keccak256("")); + return (attestations[ref_id][index].data,attestations[ref_id][index].opposite_party_id,attestations[ref_id][index].attest_level,attestations[ref_id][index].active); + } + //function to get claim attest_level + function getClaimLevel(string uid1,string ref_id) public view returns(uint256) { + return claims[uid1][ref_id].attest_level; + } + //function to claim done by user + function getClaimDoneByUser(string uid1,string ref_id) public view returns(string) { + return claims[uid1][ref_id].claim; + } + function setClaimLevel(string uid1,string ref_id,uint256 level) checkOwner(msg.sender) public { + claims[uid1][ref_id].attest_level=level; + } + //function to delete old claim + function deleteOldClaim(string uid1,string ref_id) checkOwner(msg.sender) public { + delete claims[uid1][ref_id]; + } + +} \ No newline at end of file diff --git a/contracts/Attestation.sol b/contracts/Attestation.sol index 4bfe20a..7e7e26d 100644 --- a/contracts/Attestation.sol +++ b/contracts/Attestation.sol @@ -1,11 +1,38 @@ pragma solidity ^0.4.19; - +import "./AttestStorage.sol"; contract Attestation { - - event Attest(address _address,string _type,string _data); - - function write(string _type,string _data) public returns (bool) { - Attest(msg.sender,_type,_data); - return true; - } -} + AttestStorage storageAddress; + event claimAdded(string _by,string ref_id,string claim); + event attestDone(string _for,string _by,string ref_id,uint256 level); + //constructor to set storage address + function Attestation (address _addr) { + storageAddress=AttestStorage(_addr); + } + //function to claim | can be called by anyone + function setClaim(string uid,string ref_id,string _claim) public { + storageAddress.setClaimMapping(uid,ref_id,_claim); + claimAdded(uid,ref_id,_claim); + } + //function to attest or verify a claim + function attesting(string uid1,string uid2,string ref_id,uint256 _level) public { + uint256 count = storageAddress.getCounter(ref_id); + require(keccak256(uid1)!=keccak256(uid2)&&keccak256(storageAddress.getClaimDoneByUser(uid1,ref_id))!=keccak256("")); + count++; + storageAddress.setAttestingsMapping(uid1,uid2,ref_id,_level,count); + storageAddress.setAttestCounterMapping(ref_id,count); + if(storageAddress.getClaimLevel(uid1,ref_id)<_level){ + storageAddress.setClaimLevel(uid1,ref_id,_level); + } + attestDone(uid1,uid2,ref_id,_level); + } + //function to get pagination results + function getAttestResults(uint256 index,string ref_id) public view returns(string,string,uint256,bool) { + return storageAddress.getPaginationResults(index,ref_id); + } + //function to update any current attribute like work ex,education etc + function updateAttribute(string uid,string ref_id,string _newclaim) public { + storageAddress.deleteOldClaim(uid,ref_id); + setClaim(uid,ref_id,_newclaim); + } + +} \ No newline at end of file diff --git a/contracts/Attestation_stateless.sol b/contracts/Attestation_stateless.sol new file mode 100644 index 0000000..d46c57a --- /dev/null +++ b/contracts/Attestation_stateless.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.19; + +contract Attestation_stateless { + + event Attest(address _address,string _type,string _data); + + function write(string _type,string _data) public returns (bool) { + Attest(msg.sender,_type,_data); + return true; + } +} diff --git a/contracts/SPRINGToken.sol b/contracts/SPRINGToken.sol index 85b79f6..17c27ea 100644 --- a/contracts/SPRINGToken.sol +++ b/contracts/SPRINGToken.sol @@ -51,7 +51,7 @@ contract Ownable { */ function transferOwnership(address newOwner) onlyOwner public { require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); + OwnershipTransferred(owner, newOwner); owner = newOwner; } @@ -89,7 +89,7 @@ contract Pausable is Ownable { */ function pause() onlyOwner whenNotPaused public { paused = true; - Pause(); + Pause(); } /** @@ -97,16 +97,14 @@ contract Pausable is Ownable { */ function unpause() onlyOwner whenPaused public { paused = false; - Unpause(); + Unpause(); } } contract StandardToken is ERC20,Pausable { using SafeMath for uint256; - mapping (address => uint256) public balances; mapping (address => mapping (address => uint256)) public allowed; - /** * @dev transfer token for a specified address * @param _to The address to transfer to. @@ -119,7 +117,6 @@ contract StandardToken is ERC20,Pausable { Transfer(msg.sender, _to, _value); return true; } - /** * @dev Transfer tokens from one address to another * @param _from address The address which you want to send tokens from @@ -131,7 +128,7 @@ contract StandardToken is ERC20,Pausable { balances[_to] = balances[_to].add(_value); balances[_from] = balances[_from].sub(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - Transfer(_from, _to, _value); + Transfer(_from, _to, _value); return true; } @@ -154,7 +151,7 @@ contract StandardToken is ERC20,Pausable { function approve(address _spender, uint256 _value) whenNotPaused returns (bool success) { require(allowed[msg.sender][_spender] == 0); allowed[msg.sender][_spender] = _value; - Approval(msg.sender, _spender, _value); + Approval(msg.sender, _spender, _value); return true; } @@ -174,7 +171,7 @@ contract StandardToken is ERC20,Pausable { */ function increaseApproval(address _spender, uint _addedValue) whenNotPaused public returns (bool) { allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); - Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } @@ -185,7 +182,7 @@ contract StandardToken is ERC20,Pausable { } else { allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); } - Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + Approval(msg.sender, _spender, allowed[msg.sender][_spender]); return true; } } @@ -228,7 +225,7 @@ contract SPRINGToken is StandardToken { uint256 public maxSupply; /* Contructor function to set maxSupply*/ - function SPRINGToken(uint256 _maxSupply){ + function SPRINGToken(uint256 _maxSupply) { maxSupply = _maxSupply.mul(10**decimals); } diff --git a/contracts/SPRINGToken_Upgrade.sol b/contracts/SPRINGToken_Upgrade.sol new file mode 100644 index 0000000..6ab1eb4 --- /dev/null +++ b/contracts/SPRINGToken_Upgrade.sol @@ -0,0 +1,209 @@ +pragma solidity ^0.4.19; +import "./TokenStorage.sol"; +/*The upgraded contract*/ +/** + * @title ERC20Basic + * @dev Simpler version of ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/179 + */ +contract ERC20Basic { + uint256 public totalSupply; + function balanceOf(address who) public view returns (uint256); + function transfer(address to, uint256 value) public returns (bool); + event Transfer(address indexed from, address indexed to, uint256 value); +} + +contract ERC20 is ERC20Basic { + function allowance(address owner, address spender) public view returns (uint256); + function transferFrom(address from, address to, uint256 value) public returns (bool); + function approve(address spender, uint256 value) public returns (bool); + event Approval(address indexed owner, address indexed spender, uint256 value); +} + + + +/** + * @title Pausable + * @dev Base contract which allows children to implement an emergency stop mechanism. + */ +contract Pausable is Ownable { + event Pause(); + event Unpause(); + + bool public paused = false; + + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + */ + modifier whenNotPaused() { + require(!paused); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + */ + modifier whenPaused() { + require(paused); + _; + } + + /** + * @dev called by the owner to pause, triggers stopped state + */ + function pause() onlyOwner whenNotPaused public { + paused = true; + Pause(); + } + + /** + * @dev called by the owner to unpause, returns to normal state + */ + function unpause() onlyOwner whenPaused public { + paused = false; + Unpause(); + } +} +contract StandardToken is ERC20,Pausable { + using SafeMath for uint256; + TokenStorage public Tstore; + //constructor + function StandardToken(address Tstore_address) { + Tstore=TokenStorage(Tstore_address); + } + /** + * @dev transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer(address _to, uint256 _value) whenNotPaused returns (bool success) { + require(Tstore.getBalanceFromAddress(msg.sender)>=_value&&Tstore.getBalanceFromAddress(_to)+_value>Tstore.getBalanceFromAddress(_to)); + Tstore.setBalance(msg.sender,Tstore.getBalanceFromAddress(msg.sender).sub(_value)); + Tstore.setBalance(_to,Tstore.getBalanceFromAddress(_to).add(_value)); + emit Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint256 the amout of tokens to be transfered + */ + function transferFrom(address _from, address _to, uint256 _value) whenNotPaused returns (bool success) { + require(Tstore.getBalanceFromAddress(_from)>=_value && Tstore.getAllowedAmount(_from,msg.sender)>=_value && Tstore.getBalanceFromAddress(_from)+_value>Tstore.getBalanceFromAddress(_from)); + Tstore.setBalance(_to,Tstore.getBalanceFromAddress(_to).add(_value)); + Tstore.setBalance(_from,Tstore.getBalanceFromAddress(_from).sub(_value)); + Tstore.setAllowedAmount(_from,msg.sender,Tstore.getAllowedAmount(_from,msg.sender).sub(_value)); + emit Transfer(_from, _to, _value); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return An uint256 representing the amount owned by the passed address. + */ + function balanceOf(address _owner) constant returns (uint256 balance) { + return Tstore.getBalanceFromAddress(_owner); + } + + /** + * @dev Aprove the passed address to spend the specified amount of tokens on behalf of msg.sender. + * This only works when the allowance is 0. Cannot be used to change allowance. + * https://github.com/ethereum/EIPs/issues/738#issuecomment-336277632 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve(address _spender, uint256 _value) whenNotPaused returns (bool success) { + require(Tstore.getAllowedAmount(msg.sender,_spender)==0); + Tstore.setAllowedAmount(msg.sender,_spender,_value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint256 specifing the amount of tokens still available for the spender. + */ + function allowance(address _owner, address _spender) constant returns (uint256 remaining) { + return Tstore.getAllowedAmount(_owner,_spender); + } + + /** + * To increment allowed value is better to use this function. + * From MonolithDAO Token.sol + */ + function increaseApproval(address _spender, uint _addedValue) whenNotPaused public returns (bool) { + Tstore.setAllowedAmount(msg.sender,_spender,Tstore.getAllowedAmount(msg.sender,_spender).add(_addedValue)); + emit Approval(msg.sender, _spender,Tstore.getAllowedAmount(msg.sender,_spender)); + return true; + } + + function decreaseApproval(address _spender, uint _subtractedValue) whenNotPaused public returns (bool) { + uint oldValue = Tstore.getAllowedAmount(msg.sender,_spender); + if (_subtractedValue > oldValue) { + Tstore.setAllowedAmount(msg.sender,_spender,0); + } else { + Tstore.setAllowedAmount(msg.sender,_spender,oldValue.sub(_subtractedValue)); + } + emit Approval(msg.sender, _spender,Tstore.getAllowedAmount(msg.sender,_spender)); + return true; + } +} +library SafeMath { + function mul(uint256 a, uint256 b) internal constant returns (uint256) { + uint256 c = a * b; + assert(a == 0 || c / a == b); + return c; + } + + function div(uint256 a, uint256 b) internal constant returns (uint256) { + assert(b > 0); // Solidity automatically throws when dividing by 0 + uint256 c = a / b; + // assert(a == b * c + a % b); // There is no case in which this doesn't hold + return c; + } + + function sub(uint256 a, uint256 b) internal constant returns (uint256) { + assert(b <= a); + return a - b; + } + + function add(uint256 a, uint256 b) internal constant returns (uint256) { + uint256 c = a + b; + assert(c >= a); + return c; + } +} +/* Contract class to mint tokens and transfer */ +contract SPRINGToken_Upgrade is StandardToken { + using SafeMath for uint256; + + string constant public name = 'SPRING Token'; + string constant public symbol = 'SPRING'; + uint constant public decimals = 18; + uint256 public totalSupply; + uint256 public maxSupply; + + /* Contructor function to set maxSupply*/ + function SPRINGToken_Upgrade(uint256 _maxSupply,address Tstore_address) StandardToken(Tstore_address) { + maxSupply = _maxSupply.mul(10**decimals); + } + + /** + * @dev Function to mint tokens + * @param _amount The amount of tokens to mint. + * @return A boolean that indicates if the operation was successful. + */ + function mint(uint256 _amount) onlyOwner public returns (bool) { + require (maxSupply >= (totalSupply.add(_amount))); + totalSupply = totalSupply.add(_amount); + Tstore.setBalance(msg.sender,Tstore.getBalanceFromAddress(msg.sender).add(_amount)); + emit Transfer(address(0), msg.sender, _amount); + return true; + } + +} \ No newline at end of file diff --git a/contracts/SkillAdder.sol b/contracts/SkillAdder.sol new file mode 100644 index 0000000..e80d379 --- /dev/null +++ b/contracts/SkillAdder.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.4.19; +import "./SkillStorage.sol"; +contract SkillAdder { + SkillStorage sStore; + event skillAdded(string added_By,string skill_id,string data); + event skillEndorsed(string added_By,string added_for,string skill_id,string data); + //constructor to set storage address + function SkillAdder(address _addr) { + sStore=SkillStorage(_addr); + } + function addSkill(string uid,string skill_id,string data) public { + uint256 count=sStore.getSkillCounter(uid); + count++; + sStore.addSkill(uid,skill_id,count,data); + skillAdded(uid,skill_id,data); + } + function endorse(string skill_id,string uid,string data,string _to) public { + uint256 count=sStore.getEndorsementCounter(skill_id); + count++; + sStore.endorseByUser(uid,skill_id,count,data); + skillEndorsed(uid,_to,skill_id,data); + } + function getEndorseResults(uint256 index,string skill_id) public view returns(string,string) { + return sStore.getPaginationResults(skill_id,index); + } +} \ No newline at end of file diff --git a/contracts/SkillStorage.sol b/contracts/SkillStorage.sol new file mode 100644 index 0000000..6916a30 --- /dev/null +++ b/contracts/SkillStorage.sol @@ -0,0 +1,101 @@ +pragma solidity ^0.4.19; + +contract Ownable { + address public owner; + + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + function Ownable() { + owner = msg.sender; + } + + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + + + /** + * @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) onlyOwner public { + require(newOwner != address(0)); + OwnershipTransferred(owner, newOwner); + owner = newOwner; + } + +} +contract SkillStorage is Ownable { + /** + The struct for skills,endorsements etc... + */ + struct endorse{ + string done_by; + string data; + } + struct skillStructure { + string skill_id; + string data; + } + //mapping to check for entity to skill + mapping(string=>mapping(uint256=>skillStructure)) userToSkills; + mapping(string=>uint256) userSkillsCounter; + //mapping for keeping endorsements + mapping(string=>mapping(uint256=>endorse)) endorsements; + mapping(string=>uint256) endorsementCounter; + //mapping to allow access to only some addresses + mapping(address => bool) Access_allowed; + //to check that the request is actually coming from the vanity contract + modifier checkOwner(address _add) { + require(Access_allowed[_add]==true); + _; + } + //to set the contract address + function allowAccess(address newAddr) onlyOwner public { + Access_allowed[newAddr]=true; + } + //function to add skill/update the skill mapping + function addSkill(string uid,string skill_id,uint256 count,string data) checkOwner(msg.sender) public { + userToSkills[uid][count]=skillStructure(skill_id,data); + } + //function to get skill from user id + function getSkillCounter(string uid) public view returns(uint256) { + return userSkillsCounter[uid]; + } + //function to endorse by any user + function endorseByUser(string uid1,string skill_id,uint256 count,string data) checkOwner(msg.sender) public { + uint256 length=count-1; + bool possible; + for(uint256 i=0;i uint256) public balances; + //to keep track of allowed addresses + mapping (address => mapping (address => uint256)) public allowed; + //mapping to allow access to only some addresses + mapping(address => bool) Access_allowed; + //to check that the request is actually coming from the vanity contract + modifier checkVanity(address _add) { + require(Access_allowed[_add]==true); + _; + } + //to set the contract address + function allowAccess(address newAddr) onlyOwner public { + Access_allowed[newAddr]=true; + } + //function to get balance from address + function getBalanceFromAddress(address _add) constant public returns(uint256) { + return balances[_add]; + } + //function to get amount from addresses + function getAllowedAmount(address _add1,address _add2) constant public returns(uint256) { + return allowed[_add1][_add2]; + } + //function to set balance from address + function setBalance(address _add,uint256 amt) checkVanity(msg.sender) public { + balances[_add]=amt; + } + //function to set amount allowed + function setAllowedAmount(address _add1,address _add2,uint256 amt) checkVanity(msg.sender) public { + allowed[_add1][_add2]=amt; + } +} \ No newline at end of file diff --git a/contracts/TokenVesting.sol b/contracts/TokenVesting.sol new file mode 100644 index 0000000..0a6d8fc --- /dev/null +++ b/contracts/TokenVesting.sol @@ -0,0 +1,99 @@ +pragma solidity ^0.4.19; +import "./SPRINGToken_Upgrade.sol"; + + +contract TokenVesting is Ownable { + using SafeMath for uint256; + uint256 public TotalSupply; + event Released(uint256 amount); + event VestingSet(address _beneficiary,uint256 _start,uint256 _cliff,uint256 _duration,uint256 VestingAmount,bool _revocable); + event VestingRevoke(address _beneficiary); + SPRINGToken_Upgrade springtoken; + + struct VestingStructure { + uint256 cliff; + uint256 start; + uint256 duration; + uint256 VestedAmount; + bool revocable; + } + + mapping (address => uint256) public released; + mapping (address => bool) public revoked; + mapping(address => VestingStructure) mapToStructure; + function TokenVesting(address _token){ + springtoken=SPRINGToken_Upgrade(_token); + } + //function to set the total balance + function setSupply(uint256 _supp) public onlyOwner { + TotalSupply=_supp; + } + /** + * @dev Creates a vesting contract that vests its balance of any ERC20 token to the + * _beneficiary, gradually in a linear fashion until _start + _duration. By then all + * of the balance will have vested. + * @param _beneficiary address of the beneficiary to whom vested tokens are transferred + * @param _cliff duration in seconds of the cliff in which tokens will begin to vest + * @param _start the time (as Unix time) at which point vesting starts + * @param _duration duration in seconds of the period in which the tokens will vest + * @param _revocable whether the vesting is revocable or not + */ + // beneficiary of tokens after they are released + + function SetVesting(address _beneficiary,uint256 _start,uint256 _cliff,uint256 _duration,uint256 _Vamount,bool _revocable) public onlyOwner returns(bool) { + require(_beneficiary != address(0)); + require(_cliff <= _duration); + if(_start==0) _start=now; + _cliff=_cliff.add(_start); + mapToStructure[_beneficiary]=VestingStructure(_cliff,_start,_duration,_Vamount,_revocable); + //VestingSet(_beneficiary,_start,_cliff,_duration,_revocable); + return true; + } + //function to see the vesting schedule for an address + //@param beneficiary address + function VestingSchedule(address _add) public view returns(uint256,uint256,uint256,uint256,bool) { + uint256 cliff=mapToStructure[_add].cliff; + uint256 start=mapToStructure[_add].start; + uint256 duration=mapToStructure[_add].duration; + uint256 VestedAmount=mapToStructure[_add].VestedAmount; + bool revocable=mapToStructure[_add].revocable; + return(cliff,start,duration,VestedAmount,revocable); + } + + function release() public { + uint256 unreleased = releasableAmount(msg.sender); + require(unreleased > 0&&revoked[msg.sender]==false); + released[msg.sender] = released[msg.sender].add(unreleased); + require(mapToStructure[msg.sender].VestedAmount.sub(released[msg.sender])>=0); + //to transfer tokens + springtoken.transfer(msg.sender, unreleased); + Released(unreleased); + } + + function revokeVesting(address _beneficiary) public onlyOwner returns (bool) { + require(_beneficiary != address(0)); + require(mapToStructure[_beneficiary].revocable==true); + revoked[_beneficiary]=true; + released[_beneficiary] = released[_beneficiary].add(releasableAmount(_beneficiary)); + springtoken.transfer(_beneficiary,releasableAmount(_beneficiary)); + VestingRevoke(_beneficiary); + return true; + } + + + function releasableAmount(address _add) public view returns (uint256) { + return vestedAmount(_add); + } + + function vestedAmount(address _beneficiary) public view returns (uint256) { + + uint256 totalBalance = mapToStructure[_beneficiary].VestedAmount; + if (block.timestamp < mapToStructure[_beneficiary].cliff&&revoked[_beneficiary]==false) { + return 0; + } else if (block.timestamp >= mapToStructure[_beneficiary].start.add(mapToStructure[_beneficiary].duration) || revoked[_beneficiary]) { + return totalBalance; + } else { + return totalBalance.mul(block.timestamp.div(mapToStructure[_beneficiary].duration.mul(12))); + } + } +} \ No newline at end of file diff --git a/contracts/VanityStorage.sol b/contracts/VanityStorage.sol new file mode 100644 index 0000000..005c6de --- /dev/null +++ b/contracts/VanityStorage.sol @@ -0,0 +1,97 @@ +pragma solidity ^0.4.18; +/* +** The storage contract for vanityURL_Upgradable contract +** Storage contract remains same even when logic of vanity contract is changed +*/ +contract Ownable2 { + address public owner; + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + function Ownable2() { + owner = msg.sender; + } + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner2() { + require(msg.sender == owner); + _; + } +} + +//The contract keeps track of storage +contract VanityStorage is Ownable2 { + mapping(address => bool) Access_allowed; + event Check(address add); + //to check that the request is actually coming from the vanity contract + modifier checkVanity(address _add) { + require(Access_allowed[_add]==true); + _; + } + // This declares a state variable that mapping for vanityURL to address + mapping (string => address) vanity_address_mapping; + // This declares a state variable that mapping for address to vanityURL + mapping (address => string ) address_vanity_mapping; + // This declares a state variable that mapping for vanityURL to Springrole ID + mapping (string => string) vanity_springrole_id_mapping; + // This declares a state variable that mapping for Springrole ID to vanityURL + mapping (string => string) springrole_id_vanity_mapping; + + //to set the contract address + function allowAccess(address newAddr) onlyOwner2 public { + Access_allowed[newAddr]=true; + } + + //function to retrieve address from vanity url + function retrieveWalletForVanity(string _vanity_url) constant public returns (address) { + return vanity_address_mapping[_vanity_url]; + } + //function to set vanity url and address mapping + function setWalletForVanity(address _address,string _vanity_url) checkVanity(msg.sender) public { + vanity_address_mapping[_vanity_url]=_address; + } + /* function to retrive vanity url from address */ + function retrieveVanityForWallet(address _address) constant public returns (string) { + return address_vanity_mapping[_address]; + } + //function to set address and vanity url + function setVanityForWallet(address _address,string vanity_url) checkVanity(msg.sender) public { + address_vanity_mapping[_address] = vanity_url; + } + /* function to retrive wallet springrole id from vanity url */ + function retrieveSpringroleIdForVanity(string _vanity_url) constant public returns (string) { + return vanity_springrole_id_mapping[_vanity_url]; + } + /* function to set wallet springrole id from vanity url */ + function setSpringroleIdForVanity(string _vanity_url,string springroleId) checkVanity(msg.sender) public { + vanity_springrole_id_mapping[_vanity_url]=springroleId; + } + + /* function to retrive vanity url from address */ + + function retrieveVanityForSpringroleId(string _springrole_id) constant public returns (string) { + return springrole_id_vanity_mapping[_springrole_id]; + } + /* function to set vanity url from address */ + function setVanityForSpringroleId(string _springrole_id,string vanity_url) checkVanity(msg.sender) public { + springrole_id_vanity_mapping[_springrole_id] = vanity_url; + } + //function to delete address vanity mapping + function deleteWalletVanityMapping(address _add) checkVanity(msg.sender) public { + delete address_vanity_mapping[_add]; + } + //function to delete vanity address mapping + function deleteVanityWalletMapping(string vanity) checkVanity(msg.sender) public { + delete vanity_address_mapping[vanity]; + } + //function to delete springroleId vanity mapping + function deleteSpringVanityMapping(string vanity) checkVanity(msg.sender) public { + delete springrole_id_vanity_mapping[vanity_springrole_id_mapping[vanity]]; + } + //function to delete vanity springrole id mapping + function deleteVanitySpringMapping(string vanity) checkVanity(msg.sender) public { + delete vanity_springrole_id_mapping[vanity]; + } +} \ No newline at end of file diff --git a/contracts/VanityURL.sol b/contracts/VanityURL.sol index 621e9c4..8335647 100644 --- a/contracts/VanityURL.sol +++ b/contracts/VanityURL.sol @@ -37,11 +37,11 @@ contract Ownable { /** * @dev Allows the current owner to transfer control of the contract to a newOwner. - * @param newOwner The address to transfer ownership to. + * newOwner The address to transfer ownership to. */ function transferOwnership(address newOwner) onlyOwner public { require(newOwner != address(0)); - OwnershipTransferred(owner, newOwner); + emit OwnershipTransferred(owner, newOwner); owner = newOwner; } @@ -80,7 +80,7 @@ contract Pausable is Ownable { */ function pause() onlyOwner whenNotPaused public { paused = true; - Pause(); + emit Pause(); } /** @@ -88,7 +88,7 @@ contract Pausable is Ownable { */ function unpause() onlyOwner whenPaused public { paused = false; - Unpause(); + emit Unpause(); } } @@ -163,7 +163,7 @@ contract VanityURL is Ownable,Pausable { springrole_id_vanity_mapping[_springrole_id] = _vanity_url; /* adding to address vanity mapping */ address_vanity_mapping[msg.sender] = _vanity_url; - VanityReserved(msg.sender, _vanity_url); + emit VanityReserved(msg.sender, _vanity_url); } /* @@ -224,7 +224,7 @@ contract VanityURL is Ownable,Pausable { vanity_springrole_id_mapping[_vanity_url]=_springrole_id; springrole_id_vanity_mapping[_springrole_id]=_vanity_url; - VanityReserved(msg.sender, _vanity_url); + emit VanityReserved(msg.sender, _vanity_url); } /* @@ -235,7 +235,7 @@ contract VanityURL is Ownable,Pausable { require(bytes(address_vanity_mapping[msg.sender]).length != 0); address_vanity_mapping[_to] = address_vanity_mapping[msg.sender]; vanity_address_mapping[address_vanity_mapping[msg.sender]] = _to; - VanityTransfered(msg.sender,_to,address_vanity_mapping[msg.sender]); + emit VanityTransfered(msg.sender,_to,address_vanity_mapping[msg.sender]); delete(address_vanity_mapping[msg.sender]); } @@ -249,7 +249,7 @@ contract VanityURL is Ownable,Pausable { if(vanity_address_mapping[_vanity_url] != address(0x0)) { /* Sending Vanity Transfered Event */ - VanityTransfered(vanity_address_mapping[_vanity_url],_to,_vanity_url); + emit VanityTransfered(vanity_address_mapping[_vanity_url],_to,_vanity_url); /* delete from address mapping */ delete(address_vanity_mapping[vanity_address_mapping[_vanity_url]]); /* delete from vanity mapping */ @@ -262,7 +262,7 @@ contract VanityURL is Ownable,Pausable { else { /* sending VanityReserved event */ - VanityReserved(_to, _vanity_url); + emit VanityReserved(_to, _vanity_url); } /* add new address to mapping */ vanity_address_mapping[_vanity_url] = _to; @@ -285,7 +285,7 @@ contract VanityURL is Ownable,Pausable { /* delete from vanity springrole id mapping */ delete(vanity_springrole_id_mapping[_vanity_url]); /* sending VanityReleased event */ - VanityReleased(_vanity_url); + emit VanityReleased(_vanity_url); } /* diff --git a/contracts/VanityURL_Upgrade.sol b/contracts/VanityURL_Upgrade.sol new file mode 100644 index 0000000..5aa5dea --- /dev/null +++ b/contracts/VanityURL_Upgrade.sol @@ -0,0 +1,277 @@ +pragma solidity ^0.4.18; +import "./VanityStorage.sol"; +/* The upgradable version of vanityURL contract*/ + +/** +* Contract for Vanity URL on SpringRole +* This one is the upgradable contract +* Go to beta.springrole.com to try this out! +*/ + +/** + * @title Ownable + * @dev The Ownable contract has an owner address, and provides basic authorization control + * functions, this simplifies the implementation of “user permissions”. + */ + +contract Ownable { + address public owner; + + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev The Ownable constructor sets the original `owner` of the contract to the sender + * account. + */ + function Ownable() { + owner = msg.sender; + } + + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + require(msg.sender == owner); + _; + } + /** + * @dev Allows the current owner to transfer control of the contract to a newOwner. + * newOwner The address to transfer ownership to. + */ + function transferOwnership(address newOwner) onlyOwner public { + require(newOwner != address(0)); + emit OwnershipTransferred(owner, newOwner); + owner = newOwner; + } +} +/** + * @title Pausable + * @dev Base contract which allows children to implement an emergency stop mechanism. + */ + +contract Pausable is Ownable { + event Pause(); + event Unpause(); + + bool public paused = false; + + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + */ + modifier whenNotPaused() { + require(!paused); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + */ + modifier whenPaused() { + require(paused); + _; + } + + /** + * @dev called by the owner to pause, triggers stopped state + */ + function pause() onlyOwner whenNotPaused public { + paused = true; + emit Pause(); + } + + /** + * @dev called by the owner to unpause, returns to normal state + */ + function unpause() onlyOwner whenPaused public { + paused = false; + emit Unpause(); + } +} +/** + * @title VanityURL + * @dev The VanityURL contract provides functionality to reserve vanity URLs. + The address of the vanity storage contract + * Go to https://beta.springrole.com to reserve. + */ +contract VanityURL_Upgrade is Ownable,Pausable { + VanityStorage vanityStorageaddr; + + event VanityReserved(address _to, string _vanity_url); + event VanityTransfered(address _to,address _from, string _vanity_url); + event VanityReleased(string _vanity_url); + + //constructor + //The address of vanity storage address + function VanityURL_Upgrade(address vanity_store) { + vanityStorageaddr=VanityStorage(vanity_store); + } + + /* + function to reserve vanityURL + 1. Checks if vanity is check is valid + 2. Checks if address has already a vanity url + 3. check if vanity url is used by any other or not + 4. Check if vanity url is present in any other spingrole id + 5. Transfer the token + 6. Update the mapping variables + */ + function reserve(string _vanity_url,string _springrole_id) whenNotPaused public { + _vanity_url = _toLower(_vanity_url); + require(vanityStorageaddr.retrieveWalletForVanity(_vanity_url)==address(0x0)); + require(bytes(vanityStorageaddr.retrieveVanityForWallet(msg.sender)).length == 0); + require(bytes(vanityStorageaddr.retrieveVanityForSpringroleId(_springrole_id)).length == 0); + /* adding to vanity address mapping */ + vanityStorageaddr.setWalletForVanity(msg.sender,_vanity_url); + /* adding to vanity springrole id mapping */ + vanityStorageaddr.setSpringroleIdForVanity(_vanity_url,_springrole_id); + /* adding to springrole id vanity mapping */ + vanityStorageaddr.setVanityForSpringroleId(_springrole_id,_vanity_url); + /* adding to address vanity mapping */ + vanityStorageaddr.setVanityForWallet(msg.sender,_vanity_url); + emit VanityReserved(msg.sender, _vanity_url); + } + /* + function to make lowercase + */ + + function _toLower(string str) internal returns (string) { + bytes memory bStr = bytes(str); + bytes memory bLower = new bytes(bStr.length); + for (uint i = 0; i < bStr.length; i++) { + // Uppercase character... + if ((bStr[i] >= 65) && (bStr[i] <= 90)) { + // So we add 32 to make it lowercase + bLower[i] = bytes1(int(bStr[i]) + 32); + } else { + bLower[i] = bStr[i]; + } + } + return string(bLower); + } + /* + function to verify vanityURL + 1. Minimum length 4 + 2.Maximum lenght 200 + 3.Vanity url is only alphanumeric + */ + function checkForValidity(string _vanity_url) returns (bool) { + uint length = bytes(_vanity_url).length; + require(length >= 4 && length <= 200); + for (uint i =0; i< length; i++) { + var c = bytes(_vanity_url)[i]; + if ((c < 48 || c > 122 || (c > 57 && c < 65) || (c > 90 && c < 97 )) && (c != 95)) + return false; + } + return true; + } + //this is to retreive wallet address + function retrieveWallet(string vanity) constant public returns(address) { + return vanityStorageaddr.retrieveWalletForVanity(vanity); + } + //this is to retriev the spring_role_id from storage + function retrieveSpringId(string vanity) constant public returns(string) { + return vanityStorageaddr.retrieveSpringroleIdForVanity(vanity); + } + //this is to retrive vanity from wallet + function retrieveVanity(address _address) constant public returns(string) { + return vanityStorageaddr.retrieveVanityForWallet(_address); + } + /* + function to transfer ownership for Vanity URL + */ + function transferOwnershipForVanityURL(address _to) whenNotPaused public { + require(bytes(vanityStorageaddr.retrieveVanityForWallet(_to)).length == 0); + require(bytes(vanityStorageaddr.retrieveVanityForWallet(msg.sender)).length != 0); + vanityStorageaddr.setVanityForWallet(_to,string(vanityStorageaddr.retrieveVanityForWallet(msg.sender))); + vanityStorageaddr.setWalletForVanity(_to,string(vanityStorageaddr.retrieveVanityForWallet(msg.sender))); + //vanity_address_mapping[address_vanity_mapping[msg.sender]] = _to; + emit VanityTransfered(msg.sender,_to,string(vanityStorageaddr.retrieveVanityForWallet(_to))); + vanityStorageaddr.deleteWalletVanityMapping(msg.sender); + } + /* + To release vanity by owner + */ + function releaseVanityUrl(string _vanity_url) whenNotPaused onlyOwner public { + require(vanityStorageaddr.retrieveWalletForVanity(_vanity_url)!=address(0x0)); + /* delete from address mapping */ + vanityStorageaddr.deleteWalletVanityMapping(msg.sender); + /* delete from vanity mapping */ + vanityStorageaddr.deleteVanityWalletMapping(_vanity_url); + /* delete from springrole id vanity mapping */ + vanityStorageaddr.deleteSpringVanityMapping(_vanity_url); + /* delete from vanity springrole id mapping */ + vanityStorageaddr.deleteVanitySpringMapping(_vanity_url); + /* sending VanityReleased event */ + emit VanityReleased(_vanity_url); + } + /* + function to transfer ownership for Vanity URL by Owner (Upgraded function) + */ + function reserveVanityURLByOwner(address _to,string _vanity_url,string _springrole_id,string _data) whenNotPaused onlyOwner public { + _vanity_url = _toLower(_vanity_url); + require(checkForValidity(_vanity_url)); + /* check if vanity url is being used by anyone */ + if(vanityStorageaddr.retrieveWalletForVanity(_vanity_url) != address(0x0)) + { + /* Sending Vanity Transfered Event */ + emit VanityTransfered(vanityStorageaddr.retrieveWalletForVanity(_vanity_url),_to,_vanity_url); + /* delete from address mapping */ + vanityStorageaddr.deleteWalletVanityMapping(vanityStorageaddr.retrieveWalletForVanity(_vanity_url)); + /* delete from vanity mapping */ + vanityStorageaddr.deleteVanityWalletMapping(_vanity_url); + /* delete from springrole id vanity mapping */ + vanityStorageaddr.deleteVanitySpringMapping(_vanity_url); + /* delete from vanity springrole id mapping */ + vanityStorageaddr.deleteSpringVanityMapping(_vanity_url); + } + else + { + /* sending VanityReserved event */ + emit VanityReserved(_to, _vanity_url); + } + /* add new address to mapping */ + vanityStorageaddr.setWalletForVanity(_to,_vanity_url); + vanityStorageaddr.setVanityForWallet(_to,_vanity_url); + vanityStorageaddr.setSpringroleIdForVanity(_vanity_url,_springrole_id); + vanityStorageaddr.setVanityForSpringroleId(_springrole_id,_vanity_url); + } + /* + function to change Vanity URL + 1. Checks whether vanity URL is check is valid + 2. Checks whether springrole id has already has a vanity + 3. Checks if address has already a vanity url + 4. check if vanity url is used by any other or not + 5. Check if vanity url is present in reserved keyword + 6. Update the mapping variables + */ + + function changeVanityURL(string _vanity_url, string _springrole_id) whenNotPaused public { + require(bytes(vanityStorageaddr.retrieveVanityForWallet(msg.sender)).length != 0); + require(bytes(vanityStorageaddr.retrieveVanityForSpringroleId(_springrole_id)).length == 0); + _vanity_url = _toLower(_vanity_url); + require(checkForValidity(_vanity_url)); + require(vanityStorageaddr.retrieveWalletForVanity(_vanity_url) == address(0x0)); + vanityStorageaddr.setWalletForVanity(msg.sender,_vanity_url); + vanityStorageaddr.setVanityForWallet(msg.sender,_vanity_url); + vanityStorageaddr.setSpringroleIdForVanity(_vanity_url,_springrole_id); + vanityStorageaddr.setVanityForSpringroleId(_springrole_id,_vanity_url); + emit VanityReserved(msg.sender, _vanity_url); + } + /* + function to kill contract + */ + + function kill() onlyOwner { + selfdestruct(owner); + } + + /* + transfer eth recived to owner account if any + */ + function() payable { + owner.transfer(msg.value); + } +} \ No newline at end of file diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 6870077..4d32343 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -2,8 +2,11 @@ var InviteToken = artifacts.require("./InviteToken.sol"); var VanityURL = artifacts.require("./VanityURL.sol"); var AirDrop = artifacts.require("./AirDrop.sol"); var SpringToken = artifacts.require("./SPRINGToken.sol"); -var Attestation = artifacts.require("./Attestation.sol"); - +var Attestation = artifacts.require("./Attestation_stateless.sol"); +var VanityStorage = artifacts.require("./VanityStorage.sol"); +var TokenStorage=artifacts.require("./TokenStorage.sol"); +var AttestStorage=artifacts.require("./AttestStorage.sol"); +var SkillStorage=artifacts.require("./SkillStorage.sol"); module.exports = function(deployer,network,accounts) { deployer.deploy(InviteToken,1000000).then(function() { return deployer.deploy(AirDrop, InviteToken.address); @@ -13,5 +16,13 @@ module.exports = function(deployer,network,accounts) { return deployer.deploy(Attestation); }).then(function() { return deployer.deploy(SpringToken,1000000); + }).then(function(){ + return deployer.deploy(VanityStorage); + }).then(function(){ + return deployer.deploy(TokenStorage); + }).then(function(){ + return deployer.deploy(AttestStorage); + }).then(function(){ + return deployer.deploy(SkillStorage); }); }; diff --git a/migrations/3_deploy_contracts.js b/migrations/3_deploy_contracts.js new file mode 100644 index 0000000..fbbc6b9 --- /dev/null +++ b/migrations/3_deploy_contracts.js @@ -0,0 +1,27 @@ +var VanityURL_Upgrade = artifacts.require("./VanityURL_Upgrade.sol"); +var VanityStorage = artifacts.require("./VanityStorage.sol"); +var TokenStorage=artifacts.require("./TokenStorage.sol"); +var SPRINGToken_Upgrade=artifacts.require("./SPRINGToken_Upgrade.sol"); +var AttestStorage=artifacts.require("./AttestStorage.sol"); +var Attestation_new=artifacts.require("./Attestation.sol"); +var SkillStorage=artifacts.require("./SkillStorage.sol"); +var SkillAdder=artifacts.require("./SkillAdder.sol"); +module.exports = function(deployer) { + deployer.deploy(VanityURL_Upgrade, VanityStorage.address). + then(() => { + VanityStorage.deployed().then(inst => { + //return inst.allowAccess(VanityURL_Upgrade.address); + }); + }); + deployer.deploy(SPRINGToken_Upgrade,1000000,TokenStorage.address). + then(() => { + VanityStorage.deployed().then(inst => { + //return inst.allowAccess(VanityURL_Upgrade.address); + }); + }); + deployer.deploy(Attestation_new,AttestStorage.address).then(()=>{ + }) + deployer.deploy(SkillAdder,SkillStorage.address).then(()=>{ + + }) + }; \ No newline at end of file diff --git a/migrations/4_deploy_contracts.js b/migrations/4_deploy_contracts.js new file mode 100644 index 0000000..f3ed9fa --- /dev/null +++ b/migrations/4_deploy_contracts.js @@ -0,0 +1,10 @@ + +var SPRINGToken_Upgrade=artifacts.require("./SPRINGToken_Upgrade.sol"); +var TokenVesting=artifacts.require("./TokenVesting.sol"); +module.exports = function(deployer) { + + //to deploy token vesting contract + deployer.deploy(TokenVesting,SPRINGToken_Upgrade.address).then(()=>{ + + }); + }; \ No newline at end of file diff --git a/test/5_attestation.js b/test/5_attestation.js index 9717fc9..3723efd 100644 --- a/test/5_attestation.js +++ b/test/5_attestation.js @@ -1,4 +1,4 @@ -var Attestation = artifacts.require("./Attestation.sol"); +var Attestation = artifacts.require("./Attestation_stateless.sol"); contract('Attestation', function(accounts) { diff --git a/test/6_vanitystorage.js b/test/6_vanitystorage.js new file mode 100644 index 0000000..fa3bc51 --- /dev/null +++ b/test/6_vanitystorage.js @@ -0,0 +1,132 @@ +var VanityStorage = artifacts.require("./VanityStorage.sol"); +var VanityURL_Upgrade=artifacts.require("./VanityURL_Upgrade.sol"); +contract("VanityStorage",function(accounts){ + var vanityInstance; + var vanityURLInstance; + before(function(){ + VanityURL_Upgrade.deployed().then(function(instance){ + // console.log(instance.address); + vanityInstance=instance; + return VanityStorage.deployed(); + }).then(function(instance2){ + vanityStorageInstance=instance2; + }) + }) + it("should give access to the VanityURL contract",function(){ + return vanityStorageInstance.allowAccess(vanityInstance.address,{from:accounts[0]}).then(function(ins){ + //console.log(ins); + return vanityInstance.reserve('vinay_035','srind1',{from:accounts[1]}).then(function(instance){ + return vanityInstance.retrieveWallet.call('vinay_035'); + }).then(function(result) { + // console.log(result==accounts[1]); + assert.equal(result,accounts[1],"Should be able to retrive the same wallet address"); + return vanityInstance.retrieveSpringId.call("vinay_035"); + }).then(res=>{ + assert.equal(res,'srind1',"Should be able to retrive the same springrole id"); + return vanityInstance.retrieveVanity.call(accounts[1]); + }).then(function(result) { + assert.equal(result,'vinay_035',"Should be able to retrive the same vanity"); + }).catch(function(error){ + assert.isUndefined(error,"should be able to reserve a url") + }) + }) + }); + it("should be able to set the vanity for wallet",function(){ + return vanityInstance.reserve('vinay035',"srind2",{from:accounts[1]}).then(function(instance){ + assert.isUndefined(instance,"should fail when tried to reserve already reserved keyword") + }).catch(function(error){ + assert.isDefined(error,"should fail when tried to reserve already reserved keyword") + }) + }) + it("should be able to transfer a vanity", function() { + return vanityInstance.transferOwnershipForVanityURL(accounts[3],{from:accounts[1]}).then(function(instance){ + return vanityInstance.retrieveWallet.call('vinay_035'); + }).then(function(result) { + assert.equal(result,accounts[3],"Should be able to retrive the same wallet address"); + return vanityInstance.retrieveVanity.call(accounts[3]); + }).then(function(result) { + assert.equal(result,'vinay_035',"Should be able to retrive the same vanity"); + }).catch(function(error){ + assert.isUndefined(error,"should be able to reserve a url") + }) + }); + + it("owner only should be able to release a vanity", function() { + return vanityInstance.releaseVanityUrl('casein',{from:accounts[3]}).then(function(instance){ + assert.isDefined(instance,"owner only should be able to release a vanity") + }).catch(function(error){ + assert.isDefined(error,"owner should be able to release a vanity") + }) + }); + it("owner only should be able to call reserveVanityURLByOwner", function() { + return vanityInstance.reserveVanityURLByOwner(accounts[4],'testowner','srind3','0x',{from:accounts[0]}).then(function(instance){ + + assert.isDefined(instance,"owner only should be able to call reserveVanityURLByOwner yep") + }).catch(function(error){ + assert.isDefined(error,"owner only should be able to call reserveVanityURLByOwner") + }) + }); + it("owner should be able to call reserveVanityURLByOwner and assign a vanity to any address", function() { + return vanityInstance.reserveVanityURLByOwner(accounts[4],'testowner','srind3','0x').then(function(instance){ + //console.log(instance); + return vanityInstance.retrieveWallet.call('testowner'); + }).then(function(result) { + //console.log(result) + assert.equal(result,accounts[4],"Should be able to retrive the same wallet address"); + return vanityInstance.retrieveVanity.call(accounts[4]); + }).then(function(result) { + //console.log(result); + assert.equal(result,'testowner',"Should be able to retrive the same vanity"); + }).catch(function(error){ + assert.isUndefined(error,"owner should be able to call reserveVanityURLByOwner and assign a vanity to any address") + }) + }); + it("should fail when tried to reserve non alphanumeric keywords", function() { + return vanityInstance.reserve('Vi@345').then(function(instance){ + assert.isUndefined(instance,"should fail when tried to reserve non alphanumeric keywords") + }).catch(function(error){ + assert.isDefined(error,"should fail when tried to reserve non alphanumeric keywords") + }) + }); + + it("should fail when tried to reserve less then 4 characters", function() { + return vanityInstance.reserve('van').then(function(instance){ + assert.isUndefined(instance,"should fail when tried to reserve less then 4 characters") + }).catch(function(error){ + assert.isDefined(error,"should fail when tried to reserve less then 4 characters") + }) + }); + it("should error on change vanityURL when address has no vanity", function() { + return vanityInstance.changeVanityURL('noassigned',{from:accounts[5]}).then(function(instance){ + assert.isUndefined(instance,"should error on change vanityURL when not assigned") + }).catch(function(error){ + assert.isDefined(error,"should error on change vanityURL when not assigned") + }) + }); + + it("should error on change vanityURL when vanity is in use", function() { + return vanityInstance.changeVanityURL('vinay035','srind4',{from:accounts[3]}).then(function(instance){ + assert.isUndefined(instance,"should error on change vanityURL when not assigned") + }).catch(function(error){ + assert.isDefined(error,"should error on change vanityURL when not assigned") + }) + }); + + it("should be able to change vanityURL", function() { + return vanityInstance.changeVanityURL('vinay0351','srind5',{from:accounts[3]}).then(function(instance){ + assert.isDefined(instance,"should be able to change vanityURL") + }).catch(function(error){ + console.log(error); + assert.isUndefined(error,"should be able to change vanityURL") + }) + }); + it("owner should be able to kill the contract",function(){ + return vanityInstance.kill({from:accounts[6]}).then(function(instance){ + // console.log(instance); + assert.isUndefined(instance,"owner should be able to kill the contract"); + }).catch(error=>{ + // console.log(error); + assert.isDefined(error,"owner should be able to kill the contract") + }); + }) +}); diff --git a/test/7_sprintoken_upgrade.js b/test/7_sprintoken_upgrade.js new file mode 100644 index 0000000..e3202b6 --- /dev/null +++ b/test/7_sprintoken_upgrade.js @@ -0,0 +1,497 @@ + + +var VanityStorage = artifacts.require("./TokenStorage.sol"); +var VanityURL_Upgrade=artifacts.require("./SPRINGToken_Upgrade.sol"); +var TokenVesting=artifacts.require("./TokenVesting.sol"); +contract("Spring token upgrade with token vesting",function(accounts){ + var vanityInstance; + var vanityURLInstance; + var TokenVestingInstance; + before(function(){ + VanityURL_Upgrade.deployed().then(function(instance){ + // console.log(instance.address); + vanityInstance=instance; + return VanityStorage.deployed(); + }).then(function(instance2){ + vanityStorageInstance=instance2; + return TokenVesting.deployed(); + }).then(function(instance3){ + console.log(instance3.address); + TokenVestingInstance=instance3 + }); + }) + it("should give access to the springtoken contract",function(){ + return vanityStorageInstance.allowAccess(vanityInstance.address,{from:accounts[0]}).then(function(ins){ + //console.log(ins); + return vanityInstance.mint.call(10000,{from: accounts[1]}); + }).then(function(minted) { + assert.isFalse(minted, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + it("should have decimal place of 18", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + return instance.decimals.call(); + }).then(function(decimals) { + assert.equal(decimals.valueOf(), 18, "18 decimals not found"); + }); + }); + + it("token should have a name", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + return instance.name.call(); + }).then(function(name) { + assert.isDefined(name.valueOf(), 'token should have a name'); + }); + }); + + it("token should have a symbol", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + return instance.symbol.call(); + }).then(function(symbol) { + assert.isDefined(symbol.valueOf(), 'token should have a symbol'); + }); + }); + + it("token should have a maxSupply", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + return instance.maxSupply.call(); + }).then(function(maxSupply) { + assert.isDefined(maxSupply.valueOf(), 'token should have a maxSupply'); + }); + }); + + it("token default state should be unpaused", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + return instance.paused.call(); + }).then(function(paused) { + assert.isFalse(paused.valueOf(), 'token should have a maxSupply'); + }); + }); + + it("mint should throw error when tried by non owner account", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + return instance.mint.call(10000,{from: accounts[1]}); + }).then(function(minted) { + assert.isFalse(minted, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + + it("mint should throw error when tried to mint more than max supply", function() { + var token; + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.maxSupply.call(); + }).then(function(maxSupply) { + return instance.mint(maxSupply.toNumber()+1); + }).then(function(minted) { + assert.isFalse(minted, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + it("should mint 10000 when tried by owner account", function() { + var token; + var amount = 10000; + var old_balance; + var new_balance; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.balanceOf.call(accounts[0]); + }).then(function(balance) { + old_balance = balance.toNumber(); + return token.mint(amount); + }).then(function(minted) { + return token.balanceOf.call(accounts[0]); + }).then(function(balance) { + new_balance = balance.toNumber(); + assert.equal(new_balance, old_balance+amount, "10000 tokens were not minted or not assigned to owner"); + }); + }); + + it("should transfer 10 token correctly", function() { + var token; + + // Get initial balances of first and second account. + var account_one = accounts[0]; + var account_two = accounts[1]; + + var account_one_starting_balance; + var account_two_starting_balance; + var account_one_ending_balance; + var account_two_ending_balance; + + var amount = 10; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.balanceOf.call(account_one); + }).then(function(balance) { + account_one_starting_balance = balance.toNumber(); + return token.balanceOf.call(account_two); + }).then(function(balance) { + account_two_starting_balance = balance.toNumber(); + // console.log(account_two_starting_balance); + return token.transfer(account_two, amount, {from: account_one}); + }).then(function() { + return token.balanceOf.call(account_one); + }).then(function(balance) { + account_one_ending_balance = balance.toNumber(); + // console.log(balance); + return token.balanceOf.call(account_two); + }).then(function(balance) { + account_two_ending_balance = balance.toNumber(); + // console.log(account_two_ending_balance); + assert.equal(account_one_ending_balance, account_one_starting_balance - amount, "Amount wasn't correctly taken from the sender"); + assert.equal(account_two_ending_balance, account_two_starting_balance + amount, "Amount wasn't correctly sent to the receiver"); + }); + }); + + it("should transfer should fail when low balance", function() { + var token; + + // Get initial balances of first and second account. + var account_one = accounts[2]; + var account_two = accounts[3]; + + var account_one_starting_balance; + var account_two_starting_balance; + var account_one_ending_balance; + var account_two_ending_balance; + + var amount = 10; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.balanceOf.call(account_one); + }).then(function(balance) { + account_one_starting_balance = balance.toNumber(); + return token.balanceOf.call(account_two); + }).then(function(balance) { + account_two_starting_balance = balance.toNumber(); + return token.transfer(account_two, amount, {from: account_one}); + }).then(function(result) { + assert.isFalse(result, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + + it("should approve 1 token correctly", function() { + var token; + + var amount = 1; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.approve(accounts[2],amount,{from:accounts[1]}); + }).then(function() { + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(allowance) { + assert.equal(allowance.toNumber(), amount, "Amount wasn't correctly approved"); + }); + }); + + it("should transfer 1 token correctly using 3rd approved address", function() { + var token; + + var amount = 10; + + var contract_owner = accounts[0]; + var token_owner = accounts[3]; + var spender = accounts[2]; + var transfer_to = accounts[4]; + + var allowance_before_transfer; + var allowance_after_transfer; + + var amount_transferred = 1; + + var account_one_starting_balance; + var account_two_starting_balance; + var account_one_ending_balance; + var account_two_ending_balance; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.transfer(token_owner, amount, {from: contract_owner}); + }).then(function() { + return token.balanceOf.call(token_owner); + }).then(function(balance) { + // console.log(balance); + account_one_starting_balance = balance.toNumber(); + return token.balanceOf.call(transfer_to); + }).then(function(balance) { + account_two_starting_balance = balance.toNumber(); + return token.approve(spender,amount,{from:token_owner}); + }).then(function() { + return token.allowance.call(token_owner,spender); + }).then(function(allowance) { + allowance_before_transfer = allowance.toNumber(); + return token.transferFrom(token_owner,transfer_to,amount_transferred, {from: spender}); + }).then(function() { + return token.allowance.call(token_owner,spender); + }).then(function(allowance) { + allowance_after_transfer = allowance.toNumber(); + assert.equal(allowance_after_transfer, allowance_before_transfer - amount_transferred, "Allowance not updated correctly"); + }).then(function() { + return token.balanceOf.call(token_owner); + }).then(function(balance) { + account_one_ending_balance = balance.toNumber(); + return token.balanceOf.call(transfer_to); + }).then(function(balance) { + account_two_ending_balance = balance.toNumber(); + assert.equal(account_one_ending_balance, account_one_starting_balance - amount_transferred, "Amount wasn't correctly taken from the sender"); + assert.equal(account_two_ending_balance, account_two_starting_balance + amount_transferred, "Amount wasn't correctly sent to the receiver"); + }) + }); + + it("should increase approval 1 token correctly", function() { + var token; + + var amount = 1; + + var approval_starting_balance; + var approval_ending_balance; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(balance) { + approval_starting_balance = balance.toNumber(); + return token.increaseApproval(accounts[2],amount,{from:accounts[1]}); + }).then(function(allowance) { + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(balance) { + approval_ending_balance = balance.toNumber(); + assert.equal(approval_ending_balance, approval_starting_balance + amount, "Amount wasn't correctly approved"); + }); + }); + + it("should decrease approval 1 token correctly", function() { + var token; + + var amount = 1; + + var approval_starting_balance; + var approval_ending_balance; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(balance) { + approval_starting_balance = balance.toNumber(); + return token.decreaseApproval(accounts[2],amount,{from:accounts[1]}); + }).then(function(allowance) { + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(balance) { + approval_ending_balance = balance.toNumber(); + assert.equal(approval_ending_balance, approval_starting_balance - amount, "Amount wasn't correctly approved"); + }); + }); + + it("should fail when try to approve 1 token when allowance already exists", function() { + var token; + + var amount = 1; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.approve(accounts[2],amount,{from:accounts[1]}); + }).then(function(status) { + assert.isFalse(status, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + //testing for TokenVesting + it("should tranfer the passed amount to the vesting contract from the owner account",function(){ + var token; + return VanityURL_Upgrade.deployed().then(function(instance){ + token=instance; + //console.log(TokenVestingInstance.address); + return token.transfer(TokenVestingInstance.address,100,{from:accounts[0]}); + }).then((success)=>{ + return token.balanceOf.call(TokenVestingInstance.address); + }).then((balance)=>{ + assert.equal(100,balance.toNumber(),"should be equal"); + }).catch(err=>{ + console.log(err); + assert.isUndefined(err,"No error"); + }) + }); + it("should be able add an beneficiary and the details and retrieve the details",function(){ + var token; + return TokenVesting.deployed().then((instance)=>{ + token=instance; + return token.SetVesting(accounts[8],1450656000,31536000,126144000,4,true,{from:accounts[0]}); + }).then(set=>{ + return token.VestingSchedule.call(accounts[8]) + }).then(res=>{ + // console.log(res[0]); + assert.equal(1450656000,res[1].toNumber(),"starting time is equal are equal"); + }).catch(err=>{ + console.log(err); + assert.isUndefined(err,"no error"); + }); + }); + it("beneficiary should be able to release his balance",function(){ + var token; + return TokenVesting.deployed().then((instance)=>{ + token=instance + return token.release({from:accounts[8]}) + }).then((event)=>{ + // console.log(event); + return vanityInstance.balanceOf.call(accounts[8]) + }).then(bal=>{ + // console.log(bal.toNumber()); + assert.equal(4,bal.toNumber(),"the balance should be equal") + }).catch(err=>{ + + }) + }); + it("should give an error a user tries to release more token than his vested amount",function(){ + var token; + return TokenVesting.deployed().then((instance)=>{ + token=instance + return token.release({from:accounts[8]}) + }).then((event)=>{ + // console.log(event); + assert.isUndefined(event,"throws an error"); + }).catch(err=>{ + assert.isDefined(err,"throws an error"); + }) + }); + + it("throws an error when the beneficiary tries to withdraw before cliff",function(){ + var token; + return TokenVesting.deployed().then((instance)=>{ + token=instance; + //start date is 12th may 2018 cliff 1 year and vesting 4 yrs + return token.SetVesting(accounts[9],1526127132,31536000,126144000,1,true,{from:accounts[0]}); + }).then(set=>{ + return token.VestingSchedule.call(accounts[9]) + }).then(res=>{ + // console.log(res); + return token.release({from:accounts[9]}) + }).then((ans)=>{ + assert.isUndefined(ans,"throws an error") + }).catch(err=>{ + assert.isDefined(err,"throws an error"); + }); + }); + it("vested amount should eb 0 before cliff",function(){ + var token; + return TokenVesting.deployed().then((instance)=>{ + token=instance; + //start date is 12th may 2018 cliff 1 year and vesting 4 yrs + return token.vestedAmount.call(accounts[9]); + }).then((ans)=>{ + assert.equal(ans,0,"equal"); + }).catch(err=>{ + assert.isUndefined(err,"no error"); + }); + }); + + it("owner should be able to revoke vesting",function(){ + var token; + return TokenVesting.deployed().then((instance)=>{ + token=instance; + return token.revokeVesting(accounts[9],{from:accounts[0]}); + }).then((ans)=>{ + return vanityInstance.balanceOf.call(accounts[9]) + }).then((bal)=>{ + //console.log(bal); + assert.equal(bal,1,"they are equal"); + }).catch(err=>{ + console.log(err); + assert.isUndefined(err,"they are equal"); + }); + }); + it("should be able to change paused status", function() { + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.pause(); + }).then(function() { + return token.paused.call(); + }).then(function(paused) { + assert.isTrue(paused.valueOf(), 'should be able to change paused status'); + }); + }); + + it("transfer should fail when paused", function() { + var token; + + // Get initial balances of first and second account. + var account_one = accounts[0]; + var account_two = accounts[1]; + + var account_one_starting_balance; + var account_two_starting_balance; + var account_one_ending_balance; + var account_two_ending_balance; + + var amount = 1; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.balanceOf.call(account_one); + }).then(function(balance) { + account_one_starting_balance = balance.toNumber(); + return token.balanceOf.call(account_two); + }).then(function(balance) { + account_two_starting_balance = balance.toNumber(); + return token.transfer(account_two, amount, {from: account_one}); + }).then(function(result) { + assert.isFalse(result, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + + it("approval should fail when paused", function() { + var token; + + var amount = 1; + + var approval_starting_balance; + var approval_ending_balance; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(balance) { + approval_starting_balance = balance.toNumber(); + return token.increaseApproval(accounts[2],amount,{from:accounts[1]}); + }).then(function(result) { + assert.isFalse(result, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + + it("decrease approval should fail when paused", function() { + var token; + + var amount = 1; + + var approval_starting_balance; + var approval_ending_balance; + + return VanityURL_Upgrade.deployed().then(function(instance) { + token = instance; + return token.allowance.call(accounts[1],accounts[2]); + }).then(function(balance) { + approval_starting_balance = balance.toNumber(); + return token.decreaseApproval(accounts[2],amount,{from:accounts[1]}); + }).then(function(result) { + assert.isFalse(result, "transaction should have thrown error"); + }).catch(function(err) { + assert.isDefined(err, "transaction should have thrown error"); + }); + }); + }); \ No newline at end of file diff --git a/test/8_attest_new.js b/test/8_attest_new.js new file mode 100644 index 0000000..1529732 --- /dev/null +++ b/test/8_attest_new.js @@ -0,0 +1,58 @@ +var AttestStorage=artifacts.require("./AttestStorage.sol"); +var Attestation=artifacts.require("./Attestation.sol"); +contract("NEW attestation",function(accounts){ + var storageInstance; + var attestInstance; + before(function(){ + Attestation.deployed().then(function(instance){ + // console.log(instance.address); + attestInstance=instance; + return AttestStorage.deployed(); + }).then(function(instance2){ + storageInstance=instance2; + }) + }); + it("should give access to the attest contract and set a new claim",function(){ + return storageInstance.allowAccess(attestInstance.address,{from:accounts[0]}).then(function(ins){ + return attestInstance.setClaim("u1","r1","intern at springrole",{from:accounts[0]}); + }).then(res=>{ + //console.log(res); + }) + }); + it("should throw error when user tries to attest his own claim",function(){ + return attestInstance.attesting("u1","u1","r1",4).then(function(res){ + assert.isUndefined(res,"throws an error"); + }).catch(err=>{ + assert.isDefined(err,"throws an error"); + }); + }) + it("another user should be able to attest",function(){ + return attestInstance.attesting("u1","u2","r1",4).then(function(res){ + assert.isDefined(res,"another user should be able to attest"); + }).catch(err=>{ + assert.isUndefined(err,"another user should be able to attest"); + }); + }) + it("should throw error when wrong reference is attested",function(){ + return attestInstance.attesting("u1","u2","r8",4).then(function(res){ + assert.isUndefined(res,"error"); + }).catch(err=>{ + assert.isDefined(err,"error"); + }); + }) + it("should be able to get pagination results",function(){ + return attestInstance.getAttestResults.call(1,"r1").then((res)=>{ + assert.equal("intern at springrole",res[0],"they are equal"); + }) + }) + it("should be able to update claim and level should become zero",function(){ + return attestInstance.updateAttribute("u1","r1","work").then(function(res){ + return attestInstance.attesting("u1","u2","r1",0) + }).then(res2=>{ + return attestInstance.getAttestResults.call(2,"r1"); + }).then(ans=>{ + assert.equal("work",ans[0],"equal"); + assert.equal(0,ans[2].toNumber()); + }); + }); + }); \ No newline at end of file diff --git a/test/9_skill.js b/test/9_skill.js new file mode 100644 index 0000000..a01d33b --- /dev/null +++ b/test/9_skill.js @@ -0,0 +1,55 @@ +var skillStorage=artifacts.require("./SkillStorage.sol"); +var skillAdder=artifacts.require("./SkillAdder.sol"); +contract("NEW skillAdder",function(accounts){ + var skillstorageInstance; + var skillInstance; + before(function(){ + skillAdder.deployed().then(function(instance){ + // console.log(instance.address); + skillInstance=instance; + return skillStorage.deployed(); + }).then(function(instance2){ + skillstorageInstance=instance2; + }) + }); + it("should give access to the attest contract and set a new claim",function(){ + return skillstorageInstance.allowAccess(skillInstance.address,{from:accounts[0]}).then(function(ins){ + return skillInstance.addSkill("u1","s1","c++",{from:accounts[0]}); + }).then(res=>{ + }) + }); + it("another user should be able to endorse",function(){ + return skillInstance.endorse("s1","u2","c++","u1").then(function(res){ + assert.isDefined(res,"another user should be able to attest"); + }).catch(err=>{ + assert.isUndefined(err,"another user should be able to attest"); + }); + }) + it("should be able to get pagination results",function(){ + return skillInstance.getEndorseResults.call(1,"s1").then((res)=>{ + assert.equal("c++",res[1],"they are equal"); + }) + }) + it("user cannot endorse two same skills with same refernce id",function(){ + return skillInstance.endorse("s1","u2","c++","u1").then(function(res){ + assert.isUndefined(res,"another user should be able to attest"); + }).catch(err=>{ + assert.isDefined(err,"another user should be able to attest"); + }); + }); + /** + this test case is for future use + */ + + // it("should be able to delete skill",function(){ + // return skillInstance.updateAttribute("u1","r1","work").then(function(res){ + // return skillInstance.attesting("u1","u2","r1",0) + // }).then(res2=>{ + // return skillInstance.getAttestResults.call(2,"r1"); + // }).then(ans=>{ + // console.log(ans); + // assert.equal("work",ans[4],"equal"); + // assert.equal(0,ans[2].toNumber()); + // }); + // }); + }); \ No newline at end of file