Commit 59eec0c8 authored by Chuck LeDuc Díaz's avatar Chuck LeDuc Díaz
Browse files

Merge branch 'tokenxfr' into 'master'

Implement transfer() method for token

See merge request caelum-tech/caelum-identity!15
parents 9687be45 7c9cd4c7
Pipeline #69920937 passed with stage
in 4 minutes and 13 seconds
pragma solidity ^0.5.4;
import "./ERC725.sol";
import "./Token.sol";
// From https://github.com/ERC725Alliance/erc725/blob/551bc004106b810b4bf2041c7986d457732818ec/contracts/contracts/Identity.sol
contract Identity is ERC725 {
......@@ -68,6 +69,10 @@ contract Identity is ERC725 {
emit DataChanged(_key, _value);
}
function transfer(address _token, address _to, uint256 _value) external onlyOwner {
Token(_token).transfer(_to, _value);
}
function execute(uint256 _operationType, address _to, uint256 _value, bytes calldata _data)
external
onlyOwner
......
{
"name": "@caelum-tech/identity",
"version": "1.1.0",
"version": "1.2.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......@@ -33,41 +33,6 @@
"regenerator-runtime": "^0.13.2"
}
},
"@caelum-tech/ens": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@caelum-tech/ens/-/ens-1.1.0.tgz",
"integrity": "sha512-2rgX/z7xQjjFBQ4aG7G+qRxb22LVaLVz1NUj52TdAECysx7Wjk0pqMVsYhJxrEdCRrjvwUADqLL942f4gH4HDw==",
"dev": true
},
"@caelum-tech/identity": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/@caelum-tech/identity/-/identity-0.1.2.tgz",
"integrity": "sha512-F61cjgBZkQ5IuSbsNhFh3MJds6HgXlsgWq8NhB/dIZtYPV7ezXn1Ii1G1LEII5N0SiH6g+i16MScIqIBKux1/w==",
"dev": true,
"requires": {
"ethers": "^4.0.27",
"keythereum": "^1.0.4"
}
},
"@caelum-tech/parity": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@caelum-tech/parity/-/parity-1.1.1.tgz",
"integrity": "sha512-jwk9EjlBnqR14CgLZbLFrMG5xHrfNP+/RBdsnJN1lp5nTnl0AFtPL6HnWGLGecG/KO1RpRxyis5CGLU5/RNIlQ==",
"dev": true,
"requires": {
"@caelum-tech/ens": "^1.0.0",
"@caelum-tech/identity": "^0.1.2",
"@caelum-tech/validator-set": "^1.0.0",
"ethers": "^4.0.27",
"keythereum": "^1.0.4"
}
},
"@caelum-tech/validator-set": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@caelum-tech/validator-set/-/validator-set-1.0.0.tgz",
"integrity": "sha512-9qNdYhYo3h5tUZPeeTXtNR/NrIB6w54gijCUdYuH4zjqHORxSGuU3594anlvT7EVRA3L5QhCFOzhZBQPG6Ws0Q==",
"dev": true
},
"@types/bn.js": {
"version": "4.11.5",
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz",
......
{
"name": "@caelum-tech/identity",
"version": "1.1.0",
"version": "1.2.0",
"description": "Caelum Identity library",
"main": "index.js",
"scripts": {
"build": "truffle build",
"coverage": "npm run start; npm run stop; npx solidity-coverage",
"coverage": "npx solidity-coverage",
"eslint": "npx eslint .",
"lint": "npm run eslint; npm run solium",
"npm:publish": "npm publish --access public",
"solium": "solium --dir contracts",
"start": "./node_modules/@caelum-tech/parity/scripts/startParity.sh",
"stop": "./node_modules/@caelum-tech/parity/scripts/stopParity.sh",
"test": "npm run start; truffle test; npm run stop"
"test": "truffle test"
},
"repository": {
"type": "git",
......@@ -34,7 +32,6 @@
"keythereum": "^1.0.4"
},
"devDependencies": {
"@caelum-tech/parity": "^1.1.1",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-bignumber": "^3.0.0",
......
let expect = require('chai').expect
let Parity = require('@caelum-tech/parity')
const ethers = require('ethers')
const expect = require('chai').expect
const expectThrow = require('./helpers/expectThrow.js')
const Identity = artifacts.require('./contracts/Identity.sol')
const Token = artifacts.require('./contracts/Token.sol')
let parity, wallet, identityAddr, identityContract, IdentityContract
// If ethers.js wasn't so rudimentary we could access these values
// through the contract interface, but it is and we can't.
const OPERATION_CALL = 0
const OPERATION_CREATE = 1
const OPERATION_INVALID = 333 // invented
const key = ethers.utils.formatBytes32String('test')
const value = ethers.utils.formatBytes32String('Hello World')
const valueStr = 'Hello World'
const value = ethers.utils.formatBytes32String(valueStr)
const walletAddress = '0x8ad0ba67f8088d1f990f878815173f1dafda0a55'
contract('Identity', (accounts) => {
const owner = accounts[1]
const newOwner = accounts[2]
const rando = accounts[3]
const mintee = accounts[4]
let identity, token
contract('1.1. Identity', (accounts) => {
before(async () => {
parity = new Parity('http://localhost:8545')
wallet = await parity.loadWallet(walletAddress, '59Ta_ad6_]k<PWPp')
it('Should Deploy the Identity Contract', async () => {
identity = await Identity.new(owner)
expect(await identity.owner()).to.be.equal(owner)
})
it('Blockchain should be running', () => {
expect(parity.isBlockchainRunning()).to.not.be.equal(null)
it('Should test the Identity contract payable function', async () => {
web3.eth.sendTransaction({ from: rando, to: identity.address, value: web3.utils.toWei('1', 'ether') })
})
it('Should send gas to the wallet', () => {
web3.eth.sendTransaction({ from: accounts[0], to: walletAddress, value: web3.utils.toWei('10', 'ether') })
it('Should create a token through the identity', async () => {
const iface = new ethers.utils.Interface(Token.abi)
const encodedCall = iface.deployFunction.encode(Token.bytecode, [identity.address, '1000000', 'XYZ', '18'])
const tx = await identity.execute(OPERATION_CREATE, identity.address, 0, encodedCall, { from: owner })
const tokenAddress = tx.logs[0].args[0]
token = await Token.at(tokenAddress)
expect(await token.isMinter(identity.address)).to.eq(true)
})
it('Should Deploy the Identity Contract', (done) => {
IdentityContract = require('../build/contracts/Identity.json')
parity.deployContract(wallet, IdentityContract, [wallet.address])
.then(async (testId) => {
identityAddr = testId.address
expect(identityAddr).to.not.be.equal(null)
identityContract = parity.getContract(identityAddr, IdentityContract.abi, wallet)
let owner = await identityContract.owner()
expect(owner).to.be.equal(wallet.address)
done()
})
it('Should change the owner', async () => {
await identity.changeOwner(newOwner, { from: owner })
})
it('Should test the Identity contract payable function', async () => {
web3.eth.sendTransaction({ from: accounts[1], to: identityContract.address, value: web3.utils.toWei('1', 'ether') })
it('Should proxy a transfer for the owner', async () => {
await identity.transfer(token.address, rando, '10000', { from: newOwner })
})
xit('Should change the owner', async () => {
it('Should change the owner back', async () => {
await identity.changeOwner(owner, { from: newOwner })
})
xit('Should change the owner back', async () => {
it('Should not proxy a transfer for a non-owner', async () => {
await expectThrow(identity.transfer(token.address, rando, '10000', { from: rando }))
})
it('Should work as expected : setData and getData', (done) => {
identityContract.setData(key, value)
identity.setData(key, value, { from: owner })
.then(async (tx) => {
const tx2 = await tx.wait()
console.log('setData manual after waiting: ', tx2)
return identityContract.getData(key)
expect(tx.logs[0].event).to.eq('DataChanged')
return identity.getData(key)
})
.then((resValue) => {
expect(ethers.utils.parseBytes32String(resValue)).to.be.equal('Hello World')
expect(ethers.utils.parseBytes32String(resValue)).to.be.equal(valueStr)
done()
})
})
it('Should act as a proxy', (done) => {
let newIdAddress
parity.deployContract(wallet, IdentityContract, [wallet.address])
.then(async (newId) => {
newIdAddress = newId.address
newId = parity.getContract(newIdAddress, IdentityContract.abi, wallet)
let owner = await newId.owner()
expect(owner).to.be.equal(wallet.address)
let iface = new ethers.utils.Interface(IdentityContract.abi)
// let encodedCall = iface.functions.setData.encode([ key, value ], 0, { from: wallet.address })
let encodedCall = iface.functions.setData.encode([key, value])
// console.log("Encoded call: ", encodedCall)
let tx = await identityContract.execute(OPERATION_CALL, newId.address, 0, encodedCall)
tx = await tx.wait()
console.log('tx execute after waiting: ', tx)
return newId
})
.then(async (newId) => {
console.log('** GetData 1')
let data1 = await identityContract.getData(key)
console.log(data1)
let data2 = await newId.getData(key)
console.log('** GetData 2')
console.log(data2)
done()
})
it('Should act as a proxy', async () => {
const iface = new ethers.utils.Interface(Token.abi)
const encodedCall = iface.functions.mint.encode([mintee, '1000'])
await identity.execute(OPERATION_CALL, token.address, 0, encodedCall, { from: owner })
const result = await token.balanceOf(mintee)
expect(Number(result)).to.eq(1000)
})
xit('Should act as a proxy for OPERATION_CREATE', (done) => {
it('Should not waste gas on an invalid transaction type', async () => {
await expectThrow(identity.execute(OPERATION_INVALID, token.address, 0, value, { from: owner }))
})
})
const Token = artifacts.require('./contracts/Token.sol')
const expect = require('chai').expect
contract('Token', (accounts) => {
let token
......
// adapted from https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/test/helpers/expectThrow.js
module.exports = 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
const invalidAddress = error.message.search('invalid address') >= 0
assert(invalidOpcode || outOfGas || revert || invalidAddress, `Expected throw, got '${error}' instead`)// eslint-disable-line no-undef
return
}
assert.fail('Expected throw not received') // eslint-disable-line no-undef
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment