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

add interface for receiveApproval and relevant test cases #83

Closed
wants to merge 1 commit into from
Closed
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
6 changes: 6 additions & 0 deletions contracts/ApprovalRecipient.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pragma solidity ^0.4.8;

contract ApprovalRecipient {
function receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
returns (bool success);
}
7 changes: 4 additions & 3 deletions contracts/HumanStandardToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Machine-based, rapid creation of many tokens would not necessarily need these ex
.*/

import "./StandardToken.sol";
import "./ApprovalRecipient.sol";

pragma solidity ^0.4.8;

Expand Down Expand Up @@ -45,13 +46,13 @@ contract HumanStandardToken is StandardToken {

/* Approves and then calls the receiving contract */
function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
// first approve the amount for the spender
require(approve(_spender, _value));

//call the receiveApproval function on the contract you want to be notified. This crafts the function signature manually so one doesn't have to include a contract in here just for this.
//receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)
//it is assumed when one does this that the call *should* succeed, otherwise one would use vanilla approve instead.
require(_spender.call(bytes4(bytes32(sha3("receiveApproval(address,uint256,address,bytes)"))), msg.sender, _value, this, _extraData));
require(ApprovalRecipient(_spender).receiveApproval(msg.sender, _value, this, _extraData));
return true;
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"eslint-plugin-node": "^5.1.0",
"eslint-plugin-react": "^7.1.0",
"eslint-plugin-standard": "^3.0.1",
"left-pad": "^1.1.3",
"standard": "^10.0.2"
},
"standard": {
Expand Down
24 changes: 24 additions & 0 deletions test/humanStandardToken.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const expectThrow = require('./utils').expectThrow
const HumanStandardTokenAbstraction = artifacts.require('HumanStandardToken')
const SampleRecipientSuccess = artifacts.require('SampleRecipientSuccess')
const SampleRecipientThrow = artifacts.require('SampleRecipientThrow')
const leftPad = require('left-pad')
let HST

contract('HumanStandardToken', function (accounts) {
Expand Down Expand Up @@ -89,6 +90,29 @@ contract('HumanStandardToken', function (accounts) {
return expectThrow(HST.approveAndCall.call(SRS.address, 100, '0x42', {from: accounts[0]}))
})

const EXTRA_DATA_TEST_CASES = [
'',
'0x',
'0x42',
// 24 bytes (<1 word)
`0x${leftPad('', 48, 'f')}`,
// 32 bytes (1 word)
`0x${leftPad('', 64, 'f')}`,
// 46 bytes (>1 word, <2 words)
`0x${leftPad('', 92, 'f')}`,
// 64 bytes (2 words)
`0x${leftPad('', 128, 'f')}`
]

EXTRA_DATA_TEST_CASES.forEach(extraData => {
it(`approvals: approveAndCall correctly passes _extraData (${Math.max(0, extraData.length - 2)} bytes) to the receiving contract`, async () => {
const SRS = await SampleRecipientSuccess.new({from: accounts[0]})

await HST.approveAndCall(SRS.address, 100, extraData, {from: accounts[0]})
assert.strictEqual(await SRS.extraData(), extraData === '' ? '0x' : extraData)
})
})

// bit overkill. But is for testing a bug
it('approvals: msg.sender approves accounts[1] of 100 & withdraws 20 once.', async () => {
const balance0 = await HST.balanceOf.call(accounts[0])
Expand Down