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

Audit 3.4 & 3.14 Fix ST upgrades #694

Merged
merged 3 commits into from
Jun 12, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
17 changes: 17 additions & 0 deletions contracts/mocks/MockSecurityTokenLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import "../tokens/SecurityToken.sol";
contract MockSecurityTokenLogic is SecurityToken {

event UpgradeEvent(uint256 _upgrade);
uint256 public someValue;

/**
* @notice Initialization function
Expand All @@ -27,6 +28,22 @@ contract MockSecurityTokenLogic is SecurityToken {
emit UpgradeEvent(_upgrade);
}

/**
* @notice Initialization function
* @dev Expected to be called atomically with the proxy being created, by the owner of the token
* @dev Can only be called once
*/
function initialize(address _getterDelegate, uint256 _someValue) public {
//Expected to be called atomically with the proxy being created
require(!initialized, "Already initialized");
getterDelegate = _getterDelegate;
securityTokenVersion = SemanticVersion(3, 0, 0);
updateFromRegistry();
tokenFactory = msg.sender;
initialized = true;
someValue = _someValue;
}

function newFunction(uint256 _upgrade) external {
emit UpgradeEvent(_upgrade);
}
Expand Down
14 changes: 9 additions & 5 deletions contracts/tokens/STFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ contract STFactory is ISTFactory, Ownable {

uint256 public latestUpgrade;

event LogicContractSet(string _version, address _logicContract, bytes _upgradeData);
event LogicContractSet(string _version, address _logicContract, bytes _initializationData, bytes _upgradeData);
event TokenUpgraded(
address indexed _securityToken,
uint256 indexed _version
Expand All @@ -50,13 +50,14 @@ contract STFactory is ISTFactory, Ownable {
string memory _version,
address _logicContract,
bytes memory _initializationData
)
public
)
public
{
require(_logicContract != address(0), "Invalid Address");
require(_transferManagerFactory != address(0), "Invalid Address");
require(_dataStoreFactory != address(0), "Invalid Address");
require(_polymathRegistry != address(0), "Invalid Address");
require(_initializationData.length > 4, "Invalid Initialization");
transferManagerFactory = _transferManagerFactory;
dataStoreFactory = DataStoreFactory(_dataStoreFactory);
polymathRegistry = IPolymathRegistry(_polymathRegistry);
Expand Down Expand Up @@ -136,15 +137,18 @@ contract STFactory is ISTFactory, Ownable {
* @param _logicContract Address of deployed module logic contract referenced from proxy
* @param _upgradeData Data to be passed in call to upgradeToAndCall when a token upgrades its module
*/
function setLogicContract(string calldata _version, address _logicContract, bytes calldata _upgradeData) external onlyOwner {
function setLogicContract(string calldata _version, address _logicContract, bytes calldata _initializationData, bytes calldata _upgradeData) external onlyOwner {
require(keccak256(abi.encodePacked(_version)) != keccak256(abi.encodePacked(logicContracts[latestUpgrade].version)), "Same version");
require(_logicContract != logicContracts[latestUpgrade].logicContract, "Same version");
require(_logicContract != address(0), "Invalid address");
require(_initializationData.length > 4, "Invalid Initialization");
require(_upgradeData.length > 4, "Invalid Upgrade");
maxsam4 marked this conversation as resolved.
Show resolved Hide resolved
latestUpgrade++;
logicContracts[latestUpgrade].version = _version;
logicContracts[latestUpgrade].logicContract = _logicContract;
logicContracts[latestUpgrade].upgradeData = _upgradeData;
emit LogicContractSet(_version, _logicContract, _upgradeData);
logicContracts[latestUpgrade].initializationData = _initializationData;
emit LogicContractSet(_version, _logicContract, _initializationData, _upgradeData);
}

/**
Expand Down
50 changes: 47 additions & 3 deletions test/o_security_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ contract("SecurityToken", async (accounts) => {
it("Should upgrade token logic and getter", async () => {
let mockSTGetter = await MockSTGetter.new({from: account_polymath});
let mockSecurityTokenLogic = await MockSecurityTokenLogic.new("", "", 0, {from: account_polymath});
const tokenInitBytes = {
const tokenUpgradeBytes = {
name: "upgrade",
type: "function",
inputs: [
Expand All @@ -793,8 +793,25 @@ contract("SecurityToken", async (accounts) => {
}
]
};
let tokenInitBytesCall = web3.eth.abi.encodeFunctionCall(tokenInitBytes, [mockSTGetter.address, 10]);
await I_STFactory.setLogicContract("3.0.1", mockSecurityTokenLogic.address, tokenInitBytesCall, {from: account_polymath});
let tokenUpgradeBytesCall = web3.eth.abi.encodeFunctionCall(tokenUpgradeBytes, [mockSTGetter.address, 10]);

const tokenInitBytes = {
name: "initialize",
type: "function",
inputs: [
{
type: "address",
name: "_getterDelegate"
},
{
type: "uint256",
name: "_someValue"
}
]
};
let tokenInitBytesCall = web3.eth.abi.encodeFunctionCall(tokenInitBytes, [mockSTGetter.address, 9]);

await I_STFactory.setLogicContract("3.0.1", mockSecurityTokenLogic.address, tokenInitBytesCall, tokenUpgradeBytesCall, {from: account_polymath});
// NB - the mockSecurityTokenLogic sets its internal version to 3.0.0 not 3.0.1
let tx = await I_SecurityToken.upgradeToken({from: token_owner, gas: 7000000});
assert.equal(tx.logs[0].args._major, 3);
Expand All @@ -808,6 +825,33 @@ contract("SecurityToken", async (accounts) => {
assert.equal(tx.logs[0].args._upgrade, 12);
});

it("Should deploy new upgraded token", async () => {
//xxx
const symbolUpgrade = "DETU";
const nameUpgrade = "Demo Upgrade";
await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
let tx = await I_STRProxied.registerTicker(token_owner, symbolUpgrade, nameUpgrade, { from: token_owner });
assert.equal(tx.logs[0].args._owner, token_owner);
assert.equal(tx.logs[0].args._ticker, symbolUpgrade);

await I_PolyToken.approve(I_STRProxied.address, initRegFee, { from: token_owner });
let tokenTx = await I_STRProxied.generateNewSecurityToken(name, symbolUpgrade, tokenDetails, false, token_owner, 0, { from: token_owner });
// Verify the successful generation of the security token
for (let i = 0; i < tokenTx.logs.length; i++) {
console.log("LOGS: " + i);
console.log(tx.logs[i]);
}
assert.equal(tokenTx.logs[1].args._ticker, symbolUpgrade, "SecurityToken doesn't get deployed");

let newToken = await MockSecurityTokenLogic.at(tokenTx.logs[1].args._securityTokenAddress);
let newGetter = await MockSTGetter.at(newToken.address);
assert.equal(await newGetter.getTreasuryWallet.call(), token_owner, "Incorrect wallet set")
assert.equal(await newToken.owner.call(), token_owner);
assert.equal(await newToken.initialized.call(), true);
assert.equal(await newToken.someValue.call(), 9);

});

it("Should transfer from whitelist investor1 to whitelist investor 2", async () => {
let tx = await I_GeneralTransferManager.modifyKYCData(account_investor2, fromTime, toTime, expiryTime, {
from: token_owner,
Expand Down