Skip to content
Open
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
51 changes: 51 additions & 0 deletions contracts/LDGX.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ contract LDGX is StandardToken {
address public DGX_TOKEN_STORAGE;
bool public initialized;

event Transfer(address indexed from, address indexed to, uint256 value, bytes32 indexed data);

constructor(address _dgxTokenAddress, address _dgxTokenStorage) public {
totalSupply_ = 0;
DGX_TOKEN_ADDRESS = _dgxTokenAddress;
Expand All @@ -38,6 +40,18 @@ contract LDGX is StandardToken {
require(success);
}

// transfer function to support ERC-223 <https://github.com/ethereum/EIPs/issues/223>
function transfer(address _to, uint256 _value, bytes32 _data)
public
returns (bool _success)
{
if(isContract(_to)) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just do line 147-150, and do:

if isContract(_to) {
require(line 138);
}

_success = transferToContract(_to, _value, _data);
} else {
_success = transferToAddress(_to, _value, _data);
}
}

// first deposit to make sure there is already some DGX/LDGX
function firstDeposit(uint256 _dgxIn) public {
require(!initialized);
Expand Down Expand Up @@ -111,4 +125,41 @@ contract LDGX is StandardToken {
{
_dgxLdgx = totalSupply_.mul(10**9).div(ERC20(DGX_TOKEN_ADDRESS).balanceOf(address(this)));
}

////////////////////////// PRIVATE FUNCTIONS ////////////////////////////////

function transferToContract(address _to, uint256 _value, bytes32 _data)
private
returns (bool _success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
TokenReceiver(_to).tokenFallback(msg.sender, _value, _data);
emit Transfer(msg.sender, _to, _value, _data);
_success = true;
}

function transferToAddress(address _to, uint256 _value, bytes32 _data)
private
returns (bool _success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value, _data);
_success = true;
}

function isContract(address _address)
private
constant
returns (bool)
{
uint length;
assembly {
length := extcodesize(_address)
}
return (length > 0);
}
}
12 changes: 12 additions & 0 deletions contracts/mock/MockContractWithFallback.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity ^0.4.23;

contract MockContractWithFallback {
bytes32 public latestData;
function tokenFallback(address _sender, uint256 _value, bytes32 _data)
public
returns (bool _success)
{
latestData = _data;
_success = true;
}
}
9 changes: 9 additions & 0 deletions contracts/mock/MockContractWithoutFallback.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pragma solidity ^0.4.23;

contract MockContractWithoutFallback {
bytes32 public latestData;

constructor() public {
latestData = "a";
}
}
52 changes: 52 additions & 0 deletions test/LDGX.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const a = require('awaiting');

const LDGX = artifacts.require('./LDGX.sol');
const MockValidContract = artifacts.require('./MockContractWithFallback.sol');
const MockInvalidContract = artifacts.require('./MockContractWithoutFallback.sol');

const {
deployLibraries,
Expand Down Expand Up @@ -218,6 +220,56 @@ contract('Lite DGX', function (accounts) {
});
});

describe('EIP223 transfer', function () {
let ldgxBalance;
let validContract;
let invalidContract;
before(async function () {
// deposit some DGX to get LDGX
await contracts.dgx.transferAndCall(contracts.liteDgx.address, bN(1e9), '', { from: addressOf.testUser1 });
ldgxBalance = await contracts.liteDgx.balanceOf.call(addressOf.testUser1);
// deploy necessary mock contracts
validContract = await MockValidContract.new();
invalidContract = await MockInvalidContract.new();
});
it('[can transfer to valid contract]', async function () {
const initialBalance = await contracts.liteDgx.balanceOf.call(addressOf.testUser1);
const transferAmount = bN(200);
assert.ok(await contracts.liteDgx.transfer.call(
validContract.address,
transferAmount,
'',
{ from: addressOf.testUser1 },
));
await contracts.liteDgx.transfer(validContract.address, transferAmount, '', { from: addressOf.testUser1 });
assert.deepEqual(await contracts.liteDgx.balanceOf.call(validContract.address), transferAmount);
assert.deepEqual(await contracts.liteDgx.balanceOf.call(addressOf.testUser1), initialBalance.minus(transferAmount));
});
it('[can transfer to any account address]', async function () {
const initialBalance = await contracts.liteDgx.balanceOf.call(addressOf.testUser1);
const transferAmount = bN(200);
const recipient = randomAddress();
assert.ok(await contracts.liteDgx.transfer.call(
recipient,
transferAmount,
'',
{ from: addressOf.testUser1 },
));
await contracts.liteDgx.transfer(recipient, transferAmount, '', { from: addressOf.testUser1 });
assert.deepEqual(await contracts.liteDgx.balanceOf.call(recipient), transferAmount);
assert.deepEqual(await contracts.liteDgx.balanceOf.call(addressOf.testUser1), initialBalance.minus(transferAmount));
});
it('[cannot transfer to contract without tokenFallback]: revert', async function () {
const transferAmount = bN(200);
assert(await a.failure(contracts.liteDgx.transfer.call(
invalidContract.address,
transferAmount,
'',
{ from: addressOf.testUser1 },
)));
});
});

describe('withdraw DGX', function () {
it('[withdraw more than ldgx balance]: revert', async function () {
assert(await a.failure(contracts.liteDgx.withdraw.call(
Expand Down