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

Feat/meToken transfer approval #61

Merged
merged 6 commits into from
Dec 1, 2021
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
10 changes: 10 additions & 0 deletions contracts/interfaces/IMeTokenRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ interface IMeTokenRegistry {
address _to,
address _meToken
);
event CancelTransferMeTokenOwnership(address _from, address _meToken);
event ClaimMeTokenOwnership(address _from, address _to, address _meToken);

event UpdateBalancePooled(bool add, address _meToken, uint256 _amount);
event UpdateBalanceLocked(bool add, address _meToken, uint256 _amount);

Expand Down Expand Up @@ -95,6 +98,13 @@ interface IMeTokenRegistry {
/// @param _newOwner TODO
function transferMeTokenOwnership(address _newOwner) external;

/// @notice TODO
function cancelTransferMeTokenOwnership() external;

/// @notice TODO
/// @param _oldOwner TODO
function claimMeTokenOwnership(address _oldOwner) external;

/// @notice TODO
/// @param _owner TODO
/// @return TODO
Expand Down
44 changes: 38 additions & 6 deletions contracts/registries/MeTokenRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ contract MeTokenRegistry is Ownable, IMeTokenRegistry {
IMigrationRegistry public migrationRegistry;

mapping(address => Details.MeToken) private _meTokens; // key pair: ERC20 address
// TODO: this mapping will break when multiple addresses revoke ownership to 0 address
mapping(address => address) private _owners; // key: address of owner, value: address of meToken
mapping(address => address) private _pendingOwners; // key: address of owner, value: address of pending owner

constructor(
address _foundry,
Expand Down Expand Up @@ -272,18 +274,48 @@ contract MeTokenRegistry is Ownable, IMeTokenRegistry {

/// @inheritdoc IMeTokenRegistry
function transferMeTokenOwnership(address _newOwner) external override {
require(
_pendingOwners[msg.sender] == address(0),
"transfer ownership already pending"
);
require(!isOwner(_newOwner), "_newOwner already owns a meToken");
require(_newOwner != address(0), "Cannot transfer to 0 address");
address meToken_ = _owners[msg.sender];
require(meToken_ != address(0), "meToken does not exist");
_pendingOwners[msg.sender] = _newOwner;

emit TransferMeTokenOwnership(msg.sender, _newOwner, meToken_);
}

/// @inheritdoc IMeTokenRegistry
function cancelTransferMeTokenOwnership() external override {
require(
_pendingOwners[msg.sender] != address(0),
"transferMeTokenOwnership() not initiated"
);

// TODO: what happens if multiple people want to revoke ownership to 0 address?
address _meToken = _owners[msg.sender];
require(_meToken != address(0), "meToken does not exist");

require(_meToken != address(0), "!meToken");
delete _pendingOwners[msg.sender];
emit CancelTransferMeTokenOwnership(msg.sender, _meToken);
}

/// @inheritdoc IMeTokenRegistry
function claimMeTokenOwnership(address _oldOwner) external override {
require(!isOwner(msg.sender), "Already owns a meToken");
require(msg.sender == _pendingOwners[_oldOwner], "!_pendingOwner");

address _meToken = _owners[_oldOwner];
Details.MeToken storage meToken_ = _meTokens[_meToken];
meToken_.owner = _newOwner;
_owners[msg.sender] = address(0);
_owners[_newOwner] = _meToken;

emit TransferMeTokenOwnership(msg.sender, _newOwner, _meToken);
meToken_.owner = msg.sender;
_owners[msg.sender] = _meToken;

delete _owners[_oldOwner];
delete _pendingOwners[_oldOwner];

emit ClaimMeTokenOwnership(_oldOwner, msg.sender, _meToken);
}

function setWarmup(uint256 warmup_) external onlyOwner {
Expand Down
32 changes: 25 additions & 7 deletions test/contracts/registries/MeTokenRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ describe("MeTokenRegistry.sol", () => {
toETHNumber(baseY),
reserveWeight / MAX_WEIGHT
);
console.log(` calculatedRes:${calculatedRes}`);
expect(toETHNumber(await meToken.totalSupply())).to.equal(calculatedRes);
});
});
Expand All @@ -121,7 +120,7 @@ describe("MeTokenRegistry.sol", () => {
meTokenRegistry
.connect(account3)
.transferMeTokenOwnership(account2.address)
).to.revertedWith("!meToken");
).to.revertedWith("meToken does not exist");

await expect(
meTokenRegistry.transferMeTokenOwnership(account1.address)
Expand All @@ -131,14 +130,15 @@ describe("MeTokenRegistry.sol", () => {
const meTokenAddr = await meTokenRegistry.getOwnerMeToken(
account1.address
);

const tx = await meTokenRegistry
.connect(account1)
.transferMeTokenOwnership(account2.address);

/* await expect(tx)
.to.emit(meTokenRegistry, "TransferOwnership")
.withArgs(account1.address, account2.address, meTokenAddr); */
const meTokenAddrAfter = await meTokenRegistry.getOwnerMeToken(
account1.address
);
await expect(tx)
.to.emit(meTokenRegistry, "TransferMeTokenOwnership")
.withArgs(account1.address, account2.address, meTokenAddr);
});
});

Expand All @@ -147,6 +147,24 @@ describe("MeTokenRegistry.sol", () => {
expect(await meTokenRegistry.isOwner(ethers.constants.AddressZero)).to.be
.false;
});
it("Revert if ownership is not claimed", async () => {
expect(await meTokenRegistry.isOwner(account2.address)).to.be.false;
});
it("Claim ownership should work", async () => {
const meTokenAddr = await meTokenRegistry.getOwnerMeToken(
account1.address
);
const tx = await meTokenRegistry
.connect(account2)
.claimMeTokenOwnership(account1.address);
const meTokenAddrAfter = await meTokenRegistry.getOwnerMeToken(
account2.address
);
expect(meTokenAddr).to.equal(meTokenAddrAfter);
await expect(tx)
.to.emit(meTokenRegistry, "ClaimMeTokenOwnership")
.withArgs(account1.address, account2.address, meTokenAddr);
});
it("Returns true for a meToken issuer", async () => {
expect(await meTokenRegistry.isOwner(account2.address)).to.be.true;
});
Expand Down