Skip to content
This repository was archived by the owner on Jan 18, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .solcover.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ module.exports = {
skipFiles: [
'Migrations.sol',
'test',
// Temporarily skipped
'core/SetToken.sol',
],
};
11 changes: 2 additions & 9 deletions contracts/core/SetToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { ERC20 } from "zeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import { StandardToken } from "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
import { SafeMath } from "zeppelin-solidity/contracts/math/SafeMath.sol";
import { ISetFactory } from "./interfaces/ISetFactory.sol";
import "../lib/AddressArrayUtils.sol";


/**
Expand All @@ -37,7 +36,6 @@ contract SetToken is
DetailedERC20
{
using SafeMath for uint256;
using AddressArrayUtils for address[];

/* ============ Constants ============ */

Expand Down Expand Up @@ -67,11 +65,6 @@ contract SetToken is

/* ============ Modifiers ============ */

modifier isMultipleOfNaturalUnit(uint _quantity) {
require((_quantity % naturalUnit) == 0);
_;
}

modifier isCore() {
require(
msg.sender == ISetFactory(factory).core(),
Expand Down Expand Up @@ -179,8 +172,8 @@ contract SetToken is

// This is the minimum natural unit possible for a Set with these components.
require(
_naturalUnit >= uint(10)**(18 - minDecimals),
"Set naturalUnit must be greater than minimum of component decimals"
_naturalUnit >= uint(10) ** (18 - minDecimals),
"Set naturalUnit does not work with underlying component decimals"
);

factory = _factory;
Expand Down
21 changes: 0 additions & 21 deletions contracts/lib/AddressArrayUtils.sol

This file was deleted.

25 changes: 25 additions & 0 deletions contracts/test/NoDecimalTokenMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
pragma solidity 0.4.24;


import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";


contract NoDecimalTokenMock is StandardToken {
string public name;
string public symbol;
uint256 public totalSupply;

constructor(
address initialAccount,
uint256 initialBalance,
string _name,
string _symbol)
public
{
balances[initialAccount] = initialBalance;
totalSupply = initialBalance;
name = _name;
symbol = _symbol;
}

}
162 changes: 162 additions & 0 deletions test/setToken.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,21 @@ contract("SetToken", (accounts) => {
await expectRevertError(subject());
});
});

describe("when a component does not implement decimals() and natural unit lower", async () => {
beforeEach(async () => {
const minNaturalUnit = 10 ** 18;
const noDecimalToken = await coreWrapper.deployTokenWithNoDecimalAsync(deployerAccount);
subjectComponentAddresses.push(noDecimalToken.address);
subjectComponentUnits.push(STANDARD_COMPONENT_UNIT);

subjectNaturalUnit = new BigNumber(minNaturalUnit).sub(1);
});

it("should revert", async () => {
await expectRevertError(subject());
});
});
});

describe("#mint", async () => {
Expand Down Expand Up @@ -399,4 +414,151 @@ contract("SetToken", (accounts) => {
});
});
});

describe("#transfer", async () => {
let subjectCaller: Address;
let subjectTokenReceiver: Address;
let subjectQuantityToTransfer: BigNumber;

beforeEach(async () => {
const quantityToMint = ether(5);
components = await coreWrapper.deployTokensAsync(3, deployerAccount);
factory = await coreWrapper.deploySetTokenFactoryAsync();
await coreWrapper.setCoreAddress(factory, coreAccount);

const componentAddresses = _.map(components, (token) => token.address);
const componentUnits = _.map(components, () => ether(randomIntegerLessThan(4)));
setToken = await coreWrapper.deploySetTokenAsync(
factory.address,
componentAddresses,
componentUnits,
STANDARD_NATURAL_UNIT,
"Set Token",
"SET",
);

await setToken.mint.sendTransactionAsync(
deployerAccount,
quantityToMint,
{ from: coreAccount },
);

subjectCaller = deployerAccount;
subjectTokenReceiver = otherAccount;
subjectQuantityToTransfer = STANDARD_NATURAL_UNIT;
});

async function subject(): Promise<string> {
return setToken.transfer.sendTransactionAsync(
subjectTokenReceiver,
subjectQuantityToTransfer,
{ from: subjectCaller },
);
}

it("transfers the tokens to the right receiver", async () => {
const existingReceiverBalance = await setToken.balanceOf.callAsync(subjectTokenReceiver);

await subject();

const newReceiverBalance = await setToken.balanceOf.callAsync(subjectTokenReceiver);
expect(newReceiverBalance).to.be.bignumber.equal(existingReceiverBalance.add(subjectQuantityToTransfer));
});

describe("when the destination is null address", async () => {
beforeEach(async () => {
subjectTokenReceiver = NULL_ADDRESS;
});

it("should revert", async () => {
await expectRevertError(subject());
});
});

describe("when the destination is set token address", async () => {
beforeEach(async () => {
subjectTokenReceiver = setToken.address;
});

it("should revert", async () => {
await expectRevertError(subject());
});
});
});

describe("#transferFrom", async () => {
let subjectCaller: Address;
let subjectTokenReceiver: Address;
let subjectTokenSender: Address;
let subjectQuantityToTransfer: BigNumber;

beforeEach(async () => {
const quantityToMint = ether(5);
components = await coreWrapper.deployTokensAsync(3, deployerAccount);
factory = await coreWrapper.deploySetTokenFactoryAsync();
await coreWrapper.setCoreAddress(factory, coreAccount);

const componentAddresses = _.map(components, (token) => token.address);
const componentUnits = _.map(components, () => ether(randomIntegerLessThan(4)));
setToken = await coreWrapper.deploySetTokenAsync(
factory.address,
componentAddresses,
componentUnits,
STANDARD_NATURAL_UNIT,
"Set Token",
"SET",
);

await setToken.mint.sendTransactionAsync(
deployerAccount,
quantityToMint,
{ from: coreAccount },
);

await coreWrapper.approveTransferAsync(setToken, deployerAccount, deployerAccount);

subjectCaller = deployerAccount;
subjectTokenReceiver = otherAccount;
subjectTokenSender = deployerAccount
subjectQuantityToTransfer = STANDARD_NATURAL_UNIT;
});

async function subject(): Promise<string> {
return setToken.transferFrom.sendTransactionAsync(
subjectTokenSender,
subjectTokenReceiver,
subjectQuantityToTransfer,
{ from: subjectCaller },
);
}

it("transfers the tokens to the right receiver", async () => {
const existingReceiverBalance = await setToken.balanceOf.callAsync(subjectTokenReceiver);

await subject();

const newReceiverBalance = await setToken.balanceOf.callAsync(subjectTokenReceiver);
expect(newReceiverBalance).to.be.bignumber.equal(existingReceiverBalance.add(subjectQuantityToTransfer));
});

describe("when the destination is null address", async () => {
beforeEach(async () => {
subjectTokenReceiver = NULL_ADDRESS;
});

it("should revert", async () => {
await expectRevertError(subject());
});
});

describe("when the destination is set token address", async () => {
beforeEach(async () => {
subjectTokenReceiver = setToken.address;
});

it("should revert", async () => {
await expectRevertError(subject());
});
});
});
});
24 changes: 24 additions & 0 deletions test/utils/coreWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CoreContract } from "../../types/generated/core";
import { StandardTokenContract } from "../../types/generated/standard_token";
import { StandardTokenMockContract } from "../../types/generated/standard_token_mock";
import { StandardTokenWithFeeMockContract } from "../../types/generated/standard_token_with_fee_mock";
import { NoDecimalTokenMockContract } from "../../types/generated/no_decimal_token_mock";
import { TransferProxyContract } from "../../types/generated/transfer_proxy";

import { VaultContract } from "../../types/generated/vault";
Expand All @@ -32,6 +33,7 @@ const TransferProxy = artifacts.require("TransferProxy");
const SetTokenFactory = artifacts.require("SetTokenFactory");
const StandardTokenMock = artifacts.require("StandardTokenMock");
const StandardTokenWithFeeMock = artifacts.require("StandardTokenWithFeeMock");
const NoDecimalTokenMock = artifacts.require("NoDecimalTokenMock");
const Vault = artifacts.require("Vault");
const SetToken = artifacts.require("SetToken");

Expand Down Expand Up @@ -97,6 +99,28 @@ export class CoreWrapper {
);
}

public async deployTokenWithNoDecimalAsync(
initialAccount: Address,
from: Address = this._tokenOwnerAddress
): Promise<NoDecimalTokenMockContract> {
const truffleMockToken = await NoDecimalTokenMock.new(
initialAccount,
DEPLOYED_TOKEN_QUANTITY,
"No Decimal Token",
"NDT",
{ from, gas: DEFAULT_GAS },
);

const mockTokenWeb3Contract = web3.eth
.contract(truffleMockToken.abi)
.at(truffleMockToken.address);

return new NoDecimalTokenMockContract(
mockTokenWeb3Contract,
{ from },
);
}

public async deployTokensAsync(
tokenCount: number,
initialAccount: Address,
Expand Down