Skip to content

Commit

Permalink
Address list renamed to address set and make adding elements idempote…
Browse files Browse the repository at this point in the history
…nt. (#917)
  • Loading branch information
zyzek authored Nov 20, 2020
1 parent 741e348 commit 2fdd05d
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 71 deletions.
62 changes: 0 additions & 62 deletions contracts/AddressListLib.sol

This file was deleted.

65 changes: 65 additions & 0 deletions contracts/AddressSetLib.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
pragma solidity ^0.5.16;


// https://docs.synthetix.io/contracts/source/libraries/addresssetlib/
library AddressSetLib {
struct AddressSet {
address[] elements;
mapping(address => uint) indices;
}

function contains(AddressSet storage set, address candidate) internal view returns (bool) {
if (set.elements.length == 0) {
return false;
}
uint index = set.indices[candidate];
return index != 0 || set.elements[0] == candidate;
}

function getPage(
AddressSet storage set,
uint index,
uint pageSize
) internal view returns (address[] memory) {
// NOTE: This implementation should be converted to slice operators if the compiler is updated to v0.6.0+
uint endIndex = index + pageSize; // The check below that endIndex <= index handles overflow.

// If the page extends past the end of the list, truncate it.
if (endIndex > set.elements.length) {
endIndex = set.elements.length;
}
if (endIndex <= index) {
return new address[](0);
}

uint n = endIndex - index; // We already checked for negative overflow.
address[] memory page = new address[](n);
for (uint i; i < n; i++) {
page[i] = set.elements[i + index];
}
return page;
}

function add(AddressSet storage set, address element) internal {
// Adding to a set is an idempotent operation.
if (!contains(set, element)) {
set.indices[element] = set.elements.length;
set.elements.push(element);
}
}

function remove(AddressSet storage set, address element) internal {
require(contains(set, element), "Element not in set.");
// Replace the removed element with the last element of the list.
uint index = set.indices[element];
uint lastIndex = set.elements.length - 1; // We required that element is in the list, so it is not empty.
if (index != lastIndex) {
// No need to shift the last element if it is the one we want to delete.
address shiftedElement = set.elements[lastIndex];
set.elements[index] = shiftedElement;
set.indices[shiftedElement] = index;
}
set.elements.pop();
delete set.indices[element];
}
}
18 changes: 9 additions & 9 deletions contracts/BinaryOptionMarketManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "./MixinResolver.sol";
import "./interfaces/IBinaryOptionMarketManager.sol";

// Libraries
import "./AddressListLib.sol";
import "./AddressSetLib.sol";
import "./SafeDecimalMath.sol";

// Internal references
Expand All @@ -24,7 +24,7 @@ contract BinaryOptionMarketManager is Owned, Pausable, MixinResolver, IBinaryOpt
/* ========== LIBRARIES ========== */

using SafeMath for uint;
using AddressListLib for AddressListLib.AddressList;
using AddressSetLib for AddressSetLib.AddressSet;

/* ========== TYPES ========== */

Expand Down Expand Up @@ -54,8 +54,8 @@ contract BinaryOptionMarketManager is Owned, Pausable, MixinResolver, IBinaryOpt
bool public marketCreationEnabled = true;
uint public totalDeposited;

AddressListLib.AddressList internal _activeMarkets;
AddressListLib.AddressList internal _maturedMarkets;
AddressSetLib.AddressSet internal _activeMarkets;
AddressSetLib.AddressSet internal _maturedMarkets;

BinaryOptionMarketManager internal _migratingManager;

Expand Down Expand Up @@ -275,7 +275,7 @@ contract BinaryOptionMarketManager is Owned, Pausable, MixinResolver, IBinaryOpt
[fees.poolFee, fees.creatorFee, fees.refundFee]
);
market.setResolverAndSyncCache(resolver);
_activeMarkets.push(address(market));
_activeMarkets.add(address(market));

// The debt can't be incremented in the new market's constructor because until construction is complete,
// the manager doesn't know its address in order to grant it permission.
Expand All @@ -290,7 +290,7 @@ contract BinaryOptionMarketManager is Owned, Pausable, MixinResolver, IBinaryOpt
require(_activeMarkets.contains(market), "Not an active market");
BinaryOptionMarket(market).resolve();
_activeMarkets.remove(market);
_maturedMarkets.push(market);
_maturedMarkets.add(market);
}

function cancelMarket(address market) external notPaused {
Expand Down Expand Up @@ -346,7 +346,7 @@ contract BinaryOptionMarketManager is Owned, Pausable, MixinResolver, IBinaryOpt
if (_numMarkets == 0) {
return;
}
AddressListLib.AddressList storage markets = active ? _activeMarkets : _maturedMarkets;
AddressSetLib.AddressSet storage markets = active ? _activeMarkets : _maturedMarkets;

uint runningDepositTotal;
for (uint i; i < _numMarkets; i++) {
Expand Down Expand Up @@ -375,15 +375,15 @@ contract BinaryOptionMarketManager is Owned, Pausable, MixinResolver, IBinaryOpt
if (_numMarkets == 0) {
return;
}
AddressListLib.AddressList storage markets = active ? _activeMarkets : _maturedMarkets;
AddressSetLib.AddressSet storage markets = active ? _activeMarkets : _maturedMarkets;

uint runningDepositTotal;
for (uint i; i < _numMarkets; i++) {
BinaryOptionMarket market = marketsToReceive[i];
require(!_isKnownMarket(address(market)), "Market already known.");

market.acceptOwnership();
markets.push(address(market));
markets.add(address(market));
// Update the market with the new manager address,
runningDepositTotal = runningDepositTotal.add(market.deposited());
}
Expand Down
38 changes: 38 additions & 0 deletions contracts/test-helpers/TestableAddressSet.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
pragma solidity ^0.5.16;

import "../AddressSetLib.sol";


contract TestableAddressSet {
using AddressSetLib for AddressSetLib.AddressSet;

AddressSetLib.AddressSet internal set;

function contains(address candidate) public view returns (bool) {
return set.contains(candidate);
}

function getPage(uint index, uint pageSize) public view returns (address[] memory) {
return set.getPage(index, pageSize);
}

function add(address element) public {
set.add(element);
}

function remove(address element) public {
set.remove(element);
}

function size() public view returns (uint) {
return set.elements.length;
}

function element(uint index) public view returns (address) {
return set.elements[index];
}

function index(address element) public view returns (uint) {
return set.indices[element];
}
}
Loading

0 comments on commit 2fdd05d

Please sign in to comment.