Contract Name:
ProposalsManager
Contract Source Code:
File 1 of 1 : ProposalsManager
// File: @openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File: @ethereansos/swissknife/contracts/lib/GeneralUtilities.sol
pragma solidity >=0.7.0;
library BehaviorUtilities {
function randomKey(uint256 i) internal view returns (bytes32) {
return keccak256(abi.encode(i, block.timestamp, block.number, tx.origin, tx.gasprice, block.coinbase, block.difficulty, msg.sender, blockhash(block.number - 5)));
}
function calculateProjectedArraySizeAndLoopUpperBound(uint256 arraySize, uint256 start, uint256 offset) internal pure returns(uint256 projectedArraySize, uint256 projectedArrayLoopUpperBound) {
if(arraySize != 0 && start < arraySize && offset != 0) {
uint256 length = start + offset;
if(start < (length = length > arraySize ? arraySize : length)) {
projectedArraySize = (projectedArrayLoopUpperBound = length) - start;
}
}
}
}
library ReflectionUtilities {
function read(address subject, bytes memory inputData) internal view returns(bytes memory returnData) {
bool result;
(result, returnData) = subject.staticcall(inputData);
if(!result) {
assembly {
revert(add(returnData, 0x20), mload(returnData))
}
}
}
function submit(address subject, uint256 value, bytes memory inputData) internal returns(bytes memory returnData) {
bool result;
(result, returnData) = subject.call{value : value}(inputData);
if(!result) {
assembly {
revert(add(returnData, 0x20), mload(returnData))
}
}
}
function isContract(address subject) internal view returns (bool) {
if(subject == address(0)) {
return false;
}
uint256 codeLength;
assembly {
codeLength := extcodesize(subject)
}
return codeLength > 0;
}
function clone(address originalContract) internal returns(address copyContract) {
assembly {
mstore(
0,
or(
0x5880730000000000000000000000000000000000000000803b80938091923cF3,
mul(originalContract, 0x1000000000000000000)
)
)
copyContract := create(0, 0, 32)
switch extcodesize(copyContract)
case 0 {
invalid()
}
}
}
}
library BytesUtilities {
bytes private constant ALPHABET = "0123456789abcdef";
string internal constant BASE64_ENCODER_DATA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
function asAddress(bytes memory b) internal pure returns(address) {
if(b.length == 0) {
return address(0);
}
if(b.length == 20) {
address addr;
assembly {
addr := mload(add(b, 20))
}
return addr;
}
return abi.decode(b, (address));
}
function asAddressArray(bytes memory b) internal pure returns(address[] memory callResult) {
if(b.length > 0) {
return abi.decode(b, (address[]));
}
}
function asBool(bytes memory bs) internal pure returns(bool) {
return asUint256(bs) != 0;
}
function asBoolArray(bytes memory b) internal pure returns(bool[] memory callResult) {
if(b.length > 0) {
return abi.decode(b, (bool[]));
}
}
function asBytesArray(bytes memory b) internal pure returns(bytes[] memory callResult) {
if(b.length > 0) {
return abi.decode(b, (bytes[]));
}
}
function asString(bytes memory b) internal pure returns(string memory callResult) {
if(b.length > 0) {
return abi.decode(b, (string));
}
}
function asStringArray(bytes memory b) internal pure returns(string[] memory callResult) {
if(b.length > 0) {
return abi.decode(b, (string[]));
}
}
function asUint256(bytes memory bs) internal pure returns(uint256 x) {
if (bs.length >= 32) {
assembly {
x := mload(add(bs, add(0x20, 0)))
}
}
}
function asUint256Array(bytes memory b) internal pure returns(uint256[] memory callResult) {
if(b.length > 0) {
return abi.decode(b, (uint256[]));
}
}
function toString(bytes memory data) internal pure returns(string memory) {
bytes memory str = new bytes(2 + data.length * 2);
str[0] = "0";
str[1] = "x";
for (uint256 i = 0; i < data.length; i++) {
str[2+i*2] = ALPHABET[uint256(uint8(data[i] >> 4))];
str[3+i*2] = ALPHABET[uint256(uint8(data[i] & 0x0f))];
}
return string(str);
}
function asSingletonArray(bytes memory a) internal pure returns(bytes[] memory array) {
array = new bytes[](1);
array[0] = a;
}
function toBase64(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return '';
string memory table = BASE64_ENCODER_DATA;
uint256 encodedLen = 4 * ((data.length + 2) / 3);
string memory result = new string(encodedLen + 32);
assembly {
mstore(result, encodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and(shr( 6, input), 0x3F))))
resultPtr := add(resultPtr, 1)
mstore8(resultPtr, mload(add(tablePtr, and( input, 0x3F))))
resultPtr := add(resultPtr, 1)
}
switch mod(mload(data), 3)
case 1 { mstore(sub(resultPtr, 2), shl(240, 0x3d3d)) }
case 2 { mstore(sub(resultPtr, 1), shl(248, 0x3d)) }
}
return result;
}
}
library StringUtilities {
bytes1 private constant CHAR_0 = bytes1('0');
bytes1 private constant CHAR_A = bytes1('A');
bytes1 private constant CHAR_a = bytes1('a');
bytes1 private constant CHAR_f = bytes1('f');
bytes internal constant BASE64_DECODER_DATA = hex"0000000000000000000000000000000000000000000000000000000000000000"
hex"00000000000000000000003e0000003f3435363738393a3b3c3d000000000000"
hex"00000102030405060708090a0b0c0d0e0f101112131415161718190000000000"
hex"001a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132330000000000";
function isEmpty(string memory test) internal pure returns (bool) {
return equals(test, "");
}
function equals(string memory a, string memory b) internal pure returns(bool) {
return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b));
}
function toLowerCase(string memory str) internal pure returns(string memory) {
bytes memory bStr = bytes(str);
for (uint256 i = 0; i < bStr.length; i++) {
bStr[i] = bStr[i] >= 0x41 && bStr[i] <= 0x5A ? bytes1(uint8(bStr[i]) + 0x20) : bStr[i];
}
return string(bStr);
}
function asBytes(string memory str) internal pure returns(bytes memory toDecode) {
bytes memory data = abi.encodePacked(str);
if(data.length == 0 || data[0] != "0" || (data[1] != "x" && data[1] != "X")) {
return "";
}
uint256 start = 2;
toDecode = new bytes((data.length - 2) / 2);
for(uint256 i = 0; i < toDecode.length; i++) {
toDecode[i] = bytes1(_fromHexChar(uint8(data[start++])) + _fromHexChar(uint8(data[start++])) * 16);
}
}
function toBase64(string memory input) internal pure returns(string memory) {
return BytesUtilities.toBase64(abi.encodePacked(input));
}
function fromBase64(string memory _data) internal pure returns (bytes memory) {
bytes memory data = bytes(_data);
if (data.length == 0) return new bytes(0);
require(data.length % 4 == 0, "invalid base64 decoder input");
bytes memory table = BASE64_DECODER_DATA;
uint256 decodedLen = (data.length / 4) * 3;
bytes memory result = new bytes(decodedLen + 32);
assembly {
let lastBytes := mload(add(data, mload(data)))
if eq(and(lastBytes, 0xFF), 0x3d) {
decodedLen := sub(decodedLen, 1)
if eq(and(lastBytes, 0xFFFF), 0x3d3d) {
decodedLen := sub(decodedLen, 1)
}
}
mstore(result, decodedLen)
let tablePtr := add(table, 1)
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
let resultPtr := add(result, 32)
for {} lt(dataPtr, endPtr) {}
{
dataPtr := add(dataPtr, 4)
let input := mload(dataPtr)
let output := add(
add(
shl(18, and(mload(add(tablePtr, and(shr(24, input), 0xFF))), 0xFF)),
shl(12, and(mload(add(tablePtr, and(shr(16, input), 0xFF))), 0xFF))),
add(
shl( 6, and(mload(add(tablePtr, and(shr( 8, input), 0xFF))), 0xFF)),
and(mload(add(tablePtr, and( input , 0xFF))), 0xFF)
)
)
mstore(resultPtr, shl(232, output))
resultPtr := add(resultPtr, 3)
}
}
return result;
}
function _fromHexChar(uint8 c) private pure returns (uint8) {
bytes1 charc = bytes1(c);
return charc < CHAR_0 || charc > CHAR_f ? 0 : (charc < CHAR_A ? 0 : 10) + c - uint8(charc < CHAR_A ? CHAR_0 : charc < CHAR_a ? CHAR_A : CHAR_a);
}
}
library Uint256Utilities {
function asSingletonArray(uint256 n) internal pure returns(uint256[] memory array) {
array = new uint256[](1);
array[0] = n;
}
function toHex(uint256 _i) internal pure returns (string memory) {
return BytesUtilities.toString(abi.encodePacked(_i));
}
function toString(uint256 _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint256 j = _i;
uint256 len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint256 k = len;
while (_i != 0) {
k = k-1;
uint8 temp = (48 + uint8(_i - _i / 10 * 10));
bytes1 b1 = bytes1(temp);
bstr[k] = b1;
_i /= 10;
}
return string(bstr);
}
function sum(uint256[] memory arr) internal pure returns (uint256 result) {
for(uint256 i = 0; i < arr.length; i++) {
result += arr[i];
}
}
}
library AddressUtilities {
function asSingletonArray(address a) internal pure returns(address[] memory array) {
array = new address[](1);
array[0] = a;
}
function toString(address _addr) internal pure returns (string memory) {
return _addr == address(0) ? "0x0000000000000000000000000000000000000000" : BytesUtilities.toString(abi.encodePacked(_addr));
}
}
library Bytes32Utilities {
function asSingletonArray(bytes32 a) internal pure returns(bytes32[] memory array) {
array = new bytes32[](1);
array[0] = a;
}
function toString(bytes32 bt) internal pure returns (string memory) {
return bt == bytes32(0) ? "0x0000000000000000000000000000000000000000000000000000000000000000" : BytesUtilities.toString(abi.encodePacked(bt));
}
}
library TransferUtilities {
using ReflectionUtilities for address;
function balanceOf(address erc20TokenAddress, address account) internal view returns(uint256) {
if(erc20TokenAddress == address(0)) {
return account.balance;
}
return abi.decode(erc20TokenAddress.read(abi.encodeWithSelector(IERC20(erc20TokenAddress).balanceOf.selector, account)), (uint256));
}
function allowance(address erc20TokenAddress, address account, address spender) internal view returns(uint256) {
if(erc20TokenAddress == address(0)) {
return 0;
}
return abi.decode(erc20TokenAddress.read(abi.encodeWithSelector(IERC20(erc20TokenAddress).allowance.selector, account, spender)), (uint256));
}
function safeApprove(address erc20TokenAddress, address spender, uint256 value) internal {
bytes memory returnData = erc20TokenAddress.submit(0, abi.encodeWithSelector(IERC20(erc20TokenAddress).approve.selector, spender, value));
require(returnData.length == 0 || abi.decode(returnData, (bool)), 'APPROVE_FAILED');
}
function safeTransfer(address erc20TokenAddress, address to, uint256 value) internal {
if(value == 0) {
return;
}
if(erc20TokenAddress == address(0)) {
to.submit(value, "");
return;
}
bytes memory returnData = erc20TokenAddress.submit(0, abi.encodeWithSelector(IERC20(erc20TokenAddress).transfer.selector, to, value));
require(returnData.length == 0 || abi.decode(returnData, (bool)), 'TRANSFER_FAILED');
}
function safeTransferFrom(address erc20TokenAddress, address from, address to, uint256 value) internal {
if(value == 0) {
return;
}
if(erc20TokenAddress == address(0)) {
to.submit(value, "");
return;
}
bytes memory returnData = erc20TokenAddress.submit(0, abi.encodeWithSelector(IERC20(erc20TokenAddress).transferFrom.selector, from, to, value));
require(returnData.length == 0 || abi.decode(returnData, (bool)), 'TRANSFERFROM_FAILED');
}
}
// File: @openzeppelin/contracts/utils/introspection/IERC165.sol
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
// File: @openzeppelin/contracts/token/ERC1155/IERC1155.sol
pragma solidity ^0.8.0;
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
external
view
returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
// File: @openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol
pragma solidity ^0.8.0;
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
@dev Handles the receipt of a single ERC1155 token type. This function is
called at the end of a `safeTransferFrom` after the balance has been updated.
To accept the transfer, this must return
`bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
(i.e. 0xf23a6e61, or its own function selector).
@param operator The address which initiated the transfer (i.e. msg.sender)
@param from The address which previously owned the token
@param id The ID of the token being transferred
@param value The amount of tokens being transferred
@param data Additional data with no specified format
@return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
@dev Handles the receipt of a multiple ERC1155 token types. This function
is called at the end of a `safeBatchTransferFrom` after the balances have
been updated. To accept the transfer(s), this must return
`bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
(i.e. 0xbc197c81, or its own function selector).
@param operator The address which initiated the batch transfer (i.e. msg.sender)
@param from The address which previously owned the token
@param ids An array containing ids of each token being transferred (order and length must match values array)
@param values An array containing amounts of each token being transferred (order and length must match ids array)
@param data Additional data with no specified format
@return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}
// File: @ethereansos/swissknife/contracts/generic/model/ILazyInitCapableElement.sol
pragma solidity >=0.7.0;
interface ILazyInitCapableElement is IERC165 {
function lazyInit(bytes calldata lazyInitData) external returns(bytes memory initResponse);
function initializer() external view returns(address);
event Host(address indexed from, address indexed to);
function host() external view returns(address);
function setHost(address newValue) external returns(address oldValue);
function subjectIsAuthorizedFor(address subject, address location, bytes4 selector, bytes calldata payload, uint256 value) external view returns(bool);
}
// File: @ethereansos/swissknife/contracts/generic/impl/LazyInitCapableElement.sol
pragma solidity >=0.7.0;
abstract contract LazyInitCapableElement is ILazyInitCapableElement {
using ReflectionUtilities for address;
address public override initializer;
address public override host;
constructor(bytes memory lazyInitData) {
if(lazyInitData.length > 0) {
_privateLazyInit(lazyInitData);
}
}
function lazyInit(bytes calldata lazyInitData) override external returns (bytes memory lazyInitResponse) {
return _privateLazyInit(lazyInitData);
}
function supportsInterface(bytes4 interfaceId) override external view returns(bool) {
return
interfaceId == type(IERC165).interfaceId ||
interfaceId == this.supportsInterface.selector ||
interfaceId == type(ILazyInitCapableElement).interfaceId ||
interfaceId == this.lazyInit.selector ||
interfaceId == this.initializer.selector ||
interfaceId == this.subjectIsAuthorizedFor.selector ||
interfaceId == this.host.selector ||
interfaceId == this.setHost.selector ||
_supportsInterface(interfaceId);
}
function setHost(address newValue) external override authorizedOnly returns(address oldValue) {
oldValue = host;
host = newValue;
emit Host(oldValue, newValue);
}
function subjectIsAuthorizedFor(address subject, address location, bytes4 selector, bytes calldata payload, uint256 value) public override virtual view returns(bool) {
(bool chidlElementValidationIsConsistent, bool chidlElementValidationResult) = _subjectIsAuthorizedFor(subject, location, selector, payload, value);
if(chidlElementValidationIsConsistent) {
return chidlElementValidationResult;
}
if(subject == host) {
return true;
}
if(!host.isContract()) {
return false;
}
(bool result, bytes memory resultData) = host.staticcall(abi.encodeWithSelector(ILazyInitCapableElement(host).subjectIsAuthorizedFor.selector, subject, location, selector, payload, value));
return result && abi.decode(resultData, (bool));
}
function _privateLazyInit(bytes memory lazyInitData) private returns (bytes memory lazyInitResponse) {
require(initializer == address(0), "init");
initializer = msg.sender;
(host, lazyInitResponse) = abi.decode(lazyInitData, (address, bytes));
emit Host(address(0), host);
lazyInitResponse = _lazyInit(lazyInitResponse);
}
function _lazyInit(bytes memory) internal virtual returns (bytes memory) {
return "";
}
function _supportsInterface(bytes4 selector) internal virtual view returns (bool);
function _subjectIsAuthorizedFor(address, address, bytes4, bytes calldata, uint256) internal virtual view returns(bool, bool) {
}
modifier authorizedOnly {
require(_authorizedOnly(), "unauthorized");
_;
}
function _authorizedOnly() internal returns(bool) {
return subjectIsAuthorizedFor(msg.sender, address(this), msg.sig, msg.data, msg.value);
}
}
// File: @ethereansos/swissknife/contracts/dynamicMetadata/model/IDynamicMetadataCapableElement.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;
interface IDynamicMetadataCapableElement is ILazyInitCapableElement {
function uri() external view returns(string memory);
function plainUri() external view returns(string memory);
function setUri(string calldata newValue) external returns (string memory oldValue);
function dynamicUriResolver() external view returns(address);
function setDynamicUriResolver(address newValue) external returns(address oldValue);
}
// File: contracts/core/model/IOrganization.sol
pragma solidity >=0.7.0;
interface IOrganization is IDynamicMetadataCapableElement {
struct Component {
bytes32 key;
address location;
bool active;
bool log;
}
function keyOf(address componentAddress) external view returns(bytes32);
function history(bytes32 key) external view returns(address[] memory componentsAddresses);
function batchHistory(bytes32[] calldata keys) external view returns(address[][] memory componentsAddresses);
function get(bytes32 key) external view returns(address componentAddress);
function list(bytes32[] calldata keys) external view returns(address[] memory componentsAddresses);
function isActive(address subject) external view returns(bool);
function keyIsActive(bytes32 key) external view returns(bool);
function set(Component calldata) external returns(address replacedComponentAddress);
function batchSet(Component[] calldata) external returns (address[] memory replacedComponentAddresses);
event ComponentSet(bytes32 indexed key, address indexed from, address indexed to, bool active);
function submit(address location, bytes calldata payload, address restReceiver) external payable returns(bytes memory response);
}
// File: contracts/base/model/IProposalsManager.sol
pragma solidity >=0.7.0;
interface IProposalsManager is IERC1155Receiver, ILazyInitCapableElement {
struct ProposalCode {
address location;
bytes bytecode;
}
struct ProposalCodes {
ProposalCode[] codes;
bool alsoTerminate;
}
struct Proposal {
address proposer;
address[] codeSequence;
uint256 creationBlock;
uint256 accept;
uint256 refuse;
address triggeringRules;
address[] canTerminateAddresses;
address[] validatorsAddresses;
bool validationPassed;
uint256 terminationBlock;
bytes votingTokens;
}
struct ProposalConfiguration {
address[] collections;
uint256[] objectIds;
uint256[] weights;
address creationRules;
address triggeringRules;
address[] canTerminateAddresses;
address[] validatorsAddresses;
}
function batchCreate(ProposalCodes[] calldata codeSequences) external returns(bytes32[] memory createdProposalIds);
function list(bytes32[] calldata proposalIds) external view returns(Proposal[] memory);
function votes(bytes32[] calldata proposalIds, address[] calldata voters, bytes32[][] calldata items) external view returns(uint256[][] memory accepts, uint256[][] memory refuses, uint256[][] memory toWithdraw);
function weight(bytes32 code) external view returns(uint256);
function vote(address erc20TokenAddress, bytes memory permitSignature, bytes32 proposalId, uint256 accept, uint256 refuse, address voter, bool alsoTerminate) external payable;
function batchVote(bytes[] calldata data) external payable;
function withdrawAll(bytes32[] memory proposalIds, address voterOrReceiver, bool afterTermination) external;
function terminate(bytes32[] calldata proposalIds) external;
function configuration() external view returns(ProposalConfiguration memory);
function setConfiguration(ProposalConfiguration calldata newValue) external returns(ProposalConfiguration memory oldValue);
function lastProposalId() external view returns(bytes32);
function lastVoteBlock(address voter) external view returns (uint256);
event ProposalCreated(address indexed proposer, address indexed code, bytes32 indexed proposalId);
event ProposalWeight(bytes32 indexed proposalId, address indexed collection, uint256 indexed id, bytes32 key, uint256 weight);
event ProposalTerminated(bytes32 indexed proposalId, bool result, bytes errorData);
event Accept(bytes32 indexed proposalId, address indexed voter, bytes32 indexed item, uint256 amount);
event MoveToAccept(bytes32 indexed proposalId, address indexed voter, bytes32 indexed item, uint256 amount);
event RetireAccept(bytes32 indexed proposalId, address indexed voter, bytes32 indexed item, uint256 amount);
event Refuse(bytes32 indexed proposalId, address indexed voter, bytes32 indexed item, uint256 amount);
event MoveToRefuse(bytes32 indexed proposalId, address indexed voter, bytes32 indexed item, uint256 amount);
event RetireRefuse(bytes32 indexed proposalId, address indexed voter, bytes32 indexed item, uint256 amount);
}
interface IProposalChecker {
function check(address proposalsManagerAddress, bytes32 id, bytes calldata data, address from, address voter) external view returns(bool);
}
interface IExternalProposalsManagerCommands {
function createProposalCodeSequence(bytes32 proposalId, IProposalsManager.ProposalCode[] memory codeSequenceInput, address sender) external returns (address[] memory codeSequence, IProposalsManager.ProposalConfiguration memory localConfiguration);
function proposalCanBeFinalized(bytes32 proposalId, IProposalsManager.Proposal memory proposal, bool validationPassed, bool result) external view returns (bool);
function isVotable(bytes32 proposalId, IProposalsManager.Proposal memory proposal, address from, address voter, bool voteOrWithtraw) external view returns (bytes memory response);
}
// File: contracts/base/impl/ProposalsManager.sol
pragma solidity >=0.7.0;
library ProposalsManagerLibrary {
using ReflectionUtilities for address;
function createCodeSequence(IProposalsManager.ProposalCode[] memory codeSequenceInput) external returns (address[] memory codeSequence) {
require(codeSequenceInput.length > 0, "code");
codeSequence = new address[](codeSequenceInput.length);
for(uint256 i = 0; i < codeSequenceInput.length; i++) {
address code = codeSequenceInput[i].location;
bytes memory bytecode = codeSequenceInput[i].bytecode;
if(bytecode.length > 0) {
assembly {
code := create(0, add(bytecode, 0x20), mload(bytecode))
}
}
codeSequence[i] = code;
bool isContract;
assembly {
isContract := not(iszero(extcodesize(code)))
}
require(isContract, "code");
}
}
function giveBack(address[] memory collections, uint256[] memory objectIds, uint256[] memory accepts, uint256[] memory refuses, address receiver) external returns (bool almostOne) {
for(uint256 i = 0; i < collections.length; i++) {
uint256 amount = accepts[i] + refuses[i];
if(amount == 0) {
continue;
}
if(collections[i] != address(0)) {
collections[i].submit(0, abi.encodeWithSelector(IERC1155(address(0)).safeTransferFrom.selector, address(this), receiver, objectIds[i], amount, ""));
} else {
_safeTransferOrTransferFrom(address(uint160(objectIds[i])), address(0), receiver, amount);
}
almostOne = true;
}
}
function safeTransferOrTransferFrom(address erc20TokenAddress, address from, address to, uint256 value) external {
_safeTransferOrTransferFrom(erc20TokenAddress, from, to, value);
}
function _safeTransferOrTransferFrom(address erc20TokenAddress, address from, address to, uint256 value) private {
if(value == 0) {
return;
}
if(erc20TokenAddress == address(0)) {
if(from != address(0)) {
return;
}
to.submit(value, "");
return;
}
bytes memory returnData = erc20TokenAddress.submit(0, from == address(0) ? abi.encodeWithSelector(IERC20(address(0)).transfer.selector, to, value) : abi.encodeWithSelector(IERC20(address(0)).transferFrom.selector, from, to, value));
require(returnData.length == 0 || abi.decode(returnData, (bool)));
}
function setConfiguration(IProposalsManager.ProposalConfiguration storage _configuration, IProposalsManager.ProposalConfiguration memory newValue) external returns(IProposalsManager.ProposalConfiguration memory oldValue) {
oldValue = _configuration;
require(newValue.collections.length == newValue.objectIds.length && newValue.collections.length == newValue.weights.length, "lengths");
_configuration.collections = newValue.collections;
_configuration.objectIds = newValue.objectIds;
_configuration.weights = newValue.weights;
_configuration.creationRules = newValue.creationRules;
_configuration.triggeringRules = newValue.triggeringRules;
_configuration.canTerminateAddresses = newValue.canTerminateAddresses;
_configuration.validatorsAddresses = newValue.validatorsAddresses;
}
function performAuthorizedCall(address host, bytes32 key, address subject, bytes memory inputData) external {
IOrganization organization = IOrganization(host);
organization.set(IOrganization.Component(key, subject, true, false));
(bool result, bytes memory returnData) = subject.call(inputData);
if(!result) {
returnData = abi.encode(subject, returnData);
assembly {
revert(add(returnData, 0x20), mload(returnData))
}
}
if(organization.isActive(subject)) {
organization.set(IOrganization.Component(key, address(0), false, false));
}
}
}
contract ProposalsManager is IProposalsManager, LazyInitCapableElement {
using ReflectionUtilities for address;
mapping(bytes32 => Proposal) private _proposal;
mapping(bytes32 => uint256) public override weight;
// Mapping for proposalId => address => item => weighted accept votes
mapping(bytes32 => mapping(address => mapping(bytes32 => uint256))) private _accept;
// Mapping for proposalId => address => item => weighted refuse votes
mapping(bytes32 => mapping(address => mapping(bytes32 => uint256))) private _refuse;
// If the address has withdrawed or not the given objectId
mapping(bytes32 => mapping(address => mapping(bytes32 => uint256))) private _toWithdraw;
ProposalConfiguration private _configuration;
uint256 private _keyIndex;
bool private _hostIsProposalCommand;
bytes32 public override lastProposalId;
mapping(address => uint256) public override lastVoteBlock;
constructor(bytes memory lazyInitData) LazyInitCapableElement(lazyInitData) {
}
function _lazyInit(bytes memory lazyInitData) internal override returns(bytes memory) {
(_hostIsProposalCommand, lazyInitData) = abi.decode(lazyInitData, (bool, bytes));
if(lazyInitData.length > 0) {
ProposalsManagerLibrary.setConfiguration(_configuration, abi.decode(lazyInitData, (ProposalConfiguration)));
}
return "";
}
function _supportsInterface(bytes4 interfaceId) internal override pure returns(bool) {
return
interfaceId == type(IProposalsManager).interfaceId ||
interfaceId == type(IERC1155Receiver).interfaceId;
}
bytes32[] private _toTerminate;
function batchCreate(ProposalCodes[] calldata proposalCodesArray) external override returns(bytes32[] memory createdProposalIds) {
createdProposalIds = new bytes32[](proposalCodesArray.length);
ProposalConfiguration memory standardConfiguration = _configuration;
for(uint256 i = 0; i < proposalCodesArray.length; i++) {
ProposalCodes memory proposalCodes = proposalCodesArray[i];
bytes32 proposalId = createdProposalIds[i] = lastProposalId = _randomKey();
if(proposalCodes.alsoTerminate) {
_toTerminate.push(proposalId);
}
(address[] memory codeSequence, ProposalConfiguration memory localConfiguration) =
_hostIsProposalCommand ? IExternalProposalsManagerCommands(host).createProposalCodeSequence(proposalId, proposalCodes.codes, msg.sender) :
(ProposalsManagerLibrary.createCodeSequence(proposalCodes.codes), standardConfiguration);
(address[] memory collections, uint256[] memory objectIds, uint256[] memory weights) = (
localConfiguration.collections.length > 0 ? localConfiguration.collections : standardConfiguration.collections,
localConfiguration.objectIds.length > 0 ? localConfiguration.objectIds : standardConfiguration.objectIds,
localConfiguration.weights.length > 0 ? localConfiguration.weights : standardConfiguration.weights
);
for(uint256 z = 0; z < collections.length; z++) {
bytes32 key = keccak256(abi.encodePacked(proposalId, collections[z], objectIds[z]));
emit ProposalWeight(proposalId, collections[z], objectIds[z], key, weight[key] = weights[z]);
}
(bool result, bytes memory response) = _validateRules(localConfiguration.creationRules != address(0) ? localConfiguration.creationRules : standardConfiguration.creationRules, proposalId, abi.encode(_proposal[proposalId] = Proposal(
msg.sender,
codeSequence,
block.number,
0,
0,
localConfiguration.triggeringRules != address(0) ? localConfiguration.triggeringRules : standardConfiguration.triggeringRules,
localConfiguration.canTerminateAddresses.length > 0 ? localConfiguration.canTerminateAddresses : standardConfiguration.canTerminateAddresses,
localConfiguration.validatorsAddresses.length > 0 ? localConfiguration.validatorsAddresses : standardConfiguration.validatorsAddresses,
false,
0,
abi.encode(collections, objectIds, weights)
)), msg.sender);
if(!result) {
if(response.length > 0) {
assembly {
revert(add(response, 0x20), mload(response))
}
} else {
revert("creation");
}
}
for(uint256 z = 0; z < codeSequence.length; z++) {
emit ProposalCreated(msg.sender, codeSequence[z], proposalId);
}
}
bytes32[] memory toTerminate = _toTerminate;
delete _toTerminate;
if(toTerminate.length > 0) {
terminate(toTerminate);
}
}
function list(bytes32[] calldata proposalIds) external override view returns(Proposal[] memory proposals) {
proposals = new Proposal[](proposalIds.length);
for(uint256 i = 0; i < proposalIds.length; i++) {
proposals[i] = _proposal[proposalIds[i]];
}
}
function votes(bytes32[] calldata proposalIds, address[] calldata voters, bytes32[][] calldata items) external override view returns(uint256[][] memory accepts, uint256[][] memory refuses, uint256[][] memory toWithdraw) {
accepts = new uint256[][](proposalIds.length);
refuses = new uint256[][](proposalIds.length);
toWithdraw = new uint256[][](proposalIds.length);
for(uint256 i = 0; i < proposalIds.length; i++) {
accepts[i] = new uint256[](items[i].length);
refuses[i] = new uint256[](items[i].length);
toWithdraw[i] = new uint256[](items[i].length);
for(uint256 z = 0; z < items[i].length; z++) {
accepts[i][z] = _accept[proposalIds[i]][voters[i]][items[i][z]];
refuses[i][z] = _refuse[proposalIds[i]][voters[i]][items[i][z]];
toWithdraw[i][z] = _toWithdraw[proposalIds[i]][voters[i]][items[i][z]];
}
}
}
function onERC1155Received(address operator, address from, uint256 objectId, uint256 amount, bytes calldata data) external override returns(bytes4) {
if(operator != address(this) || data.length > 0) {
_onItemReceived(from, objectId, amount, data);
}
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(address operator, address from, uint256[] calldata objectIds, uint256[] calldata amounts, bytes calldata data) external override returns (bytes4) {
if(operator != address(this) || data.length > 0) {
bytes[] memory dataArray = abi.decode(data, (bytes[]));
for(uint256 i = 0; i < objectIds.length; i++) {
_onItemReceived(from, objectIds[i], amounts[i], dataArray[i]);
}
}
return this.onERC1155BatchReceived.selector;
}
function vote(address erc20TokenAddress, bytes memory permitSignature, bytes32 proposalId, uint256 accept, uint256 refuse, address voter, bool alsoTerminate) public override payable {
if(permitSignature.length > 0) {
(uint8 v, bytes32 r, bytes32 s, uint256 deadline) = abi.decode(permitSignature, (uint8, bytes32, bytes32, uint256));
IERC20Permit(erc20TokenAddress).permit(msg.sender, address(this), (accept + refuse), deadline, v, r, s);
}
uint256 transferedValue = _safeTransferFrom(erc20TokenAddress, (accept + refuse));
require(erc20TokenAddress != address(0) || transferedValue == msg.value, "ETH");
_vote(msg.sender, address(0), uint160(erc20TokenAddress), transferedValue, proposalId, accept, refuse, voter, alsoTerminate);
}
function batchVote(bytes[] calldata data) external override payable {
for(uint256 i = 0; i < data.length; i++) {
(address erc20TokenAddress, bytes memory permitSignature, bytes32 proposalId, uint256 accept, uint256 refuse, address voter, bool alsoTerminate) = abi.decode(data[i], (address, bytes, bytes32, uint256, uint256, address, bool));
vote(erc20TokenAddress, permitSignature, proposalId, accept, refuse, voter, alsoTerminate);
}
}
function withdrawAll(bytes32[] memory proposalIds, address voterOrReceiver, bool afterTermination) external override {
bool almostOne = false;
address voter = msg.sender;
address receiver = voterOrReceiver != address(0) ? voterOrReceiver : msg.sender;
if(afterTermination) {
require(voterOrReceiver != address(0), "Mandatory");
voter = voterOrReceiver;
receiver = voterOrReceiver;
}
for(uint256 z = 0; z < proposalIds.length; z++) {
bytes32 proposalId = proposalIds[z];
(bool canVote, address[] memory collections, uint256[] memory objectIds, uint256[] memory accepts, uint256[] memory refuses) = _withdrawAll(proposalId, afterTermination ? voter : msg.sender, voter);
require(canVote ? !afterTermination : afterTermination, "termination switch");
bool result = ProposalsManagerLibrary.giveBack(collections, objectIds, accepts, refuses, receiver);
almostOne = almostOne || result;
}
require(almostOne, "No transfers");
}
function terminate(bytes32[] memory proposalIds) public override {
for(uint256 i = 0; i < proposalIds.length; i++) {
Proposal storage proposal = _proposal[proposalIds[i]];
require(proposal.terminationBlock == 0, "terminated");
require(proposal.validationPassed || _mustStopAtFirst(true, proposal.canTerminateAddresses, proposalIds[i], msg.sender, msg.sender), "Cannot Terminate");
if(!proposal.validationPassed) {
if(_mustStopAtFirst(false, proposal.validatorsAddresses, proposalIds[i], msg.sender, msg.sender)) {
_finalizeTermination(proposalIds[i], proposal, false, false);
emit ProposalTerminated(proposalIds[i], false, "");
continue;
}
}
(bool result, bytes memory errorData) = address(this).call(abi.encodeWithSelector(this.tryExecute.selector, proposal.codeSequence, abi.encodeWithSelector(0xe751f271, proposalIds[i]), new bytes[](0)));//execute(bytes32)
if(result && errorData.length == 0) {
(result, ) = _validateRules(proposal.triggeringRules, proposalIds[i], abi.encode(proposal), msg.sender);
errorData = result ? errorData : bytes("triggering");
}
_finalizeTermination(proposalIds[i], proposal, true, result && errorData.length == 0);
emit ProposalTerminated(proposalIds[i], result, errorData);
}
}
function tryExecute(address[] memory codeSequence, bytes memory inputData, bytes[] memory bytecodes) external {
require(msg.sender == address(this));
for(uint256 i = 0; i < codeSequence.length; i++) {
address codeLocation = codeSequence[i];
if(i < bytecodes.length && bytecodes[i].length > 0) {
require(codeSequence[i] == address(0), "codeLocation");
bytes memory bytecode = bytecodes[i];
uint256 codeSize;
assembly {
codeLocation := create(0, add(bytecode, 0x20), mload(bytecode))
codeSize := extcodesize(codeLocation)
}
require(codeLocation != address(0), "codeLocation");
require(codeSize > 0, "codeSize");
}
ProposalsManagerLibrary.performAuthorizedCall(host, _randomKey(), codeLocation, inputData);
}
}
function configuration() external override view returns(ProposalConfiguration memory) {
return _configuration;
}
function setConfiguration(ProposalConfiguration calldata newValue) external override authorizedOnly returns(ProposalConfiguration memory oldValue) {
return ProposalsManagerLibrary.setConfiguration(_configuration, newValue);
}
function _onItemReceived(address from, uint256 objectId, uint256 amount, bytes memory data) private {
(bytes32 proposalId, uint256 accept, uint256 refuse, address voter, bool alsoTterminate) = abi.decode(data, (bytes32, uint256, uint256, address, bool));
_vote(from, msg.sender, objectId, amount, proposalId, accept, refuse, voter, alsoTterminate);
}
function _vote(address from, address collection, uint256 objectId, uint256 amount, bytes32 proposalId, uint256 accept, uint256 refuse, address voterInput, bool alsoTterminate) private {
if(amount == 0) {
return;
}
require(amount == (accept + refuse), "amount");
address voter = voterInput == address(0) ? from : voterInput;
_ensure(proposalId, from, voter, true);
bytes32 item = keccak256(abi.encodePacked(proposalId, collection, objectId));
uint256 proposalWeight = weight[item];
require(proposalWeight > 0, "item");
_toWithdraw[proposalId][voter][item] += (accept + refuse);
if(accept > 0) {
_accept[proposalId][voter][item] += accept;
_proposal[proposalId].accept += (accept * proposalWeight);
emit Accept(proposalId, voter, item, accept);
}
if(refuse > 0) {
_refuse[proposalId][voter][item] += refuse;
_proposal[proposalId].refuse += (refuse * proposalWeight);
emit Refuse(proposalId, voter, item, refuse);
}
if(accept > 0 || refuse > 0) {
lastVoteBlock[voter] = block.number;
}
if(alsoTterminate) {
bytes32[] memory proposalIds = new bytes32[](1);
proposalIds[0] = proposalId;
terminate(proposalIds);
}
}
function _ensure(bytes32 proposalId, address from, address voter, bool voteOrWithtraw) private view returns (bool canVote) {
Proposal memory proposal = _proposal[proposalId];
require(proposal.creationBlock > 0, "proposal");
if(_hostIsProposalCommand) {
bytes memory response = IExternalProposalsManagerCommands(host).isVotable(proposalId, proposal, from, voter, voteOrWithtraw);
if(response.length > 0) {
return abi.decode(response, (bool));
}
}
bool isTerminated;
canVote = !(isTerminated = proposal.terminationBlock != 0) && !proposal.validationPassed && !_mustStopAtFirst(true, proposal.canTerminateAddresses, proposalId, from, voter);
if(voteOrWithtraw) {
require(canVote, "vote");
} else {
require(block.number > lastVoteBlock[voter], "wait 1 block");
require(!isTerminated || _proposal[proposalId].terminationBlock < block.number, "early");
}
}
function _mustStopAtFirst(bool value, address[] memory checkers, bytes32 proposalId, address from, address voter) private view returns(bool) {
if(checkers.length == 0 || (checkers.length == 1 && checkers[0] == address(0))) {
return value;
}
Proposal memory proposal = _proposal[proposalId];
bytes memory inputData = abi.encodeWithSelector(IProposalChecker(address(0)).check.selector, address(this), proposalId, abi.encode(proposal), from, voter);
for(uint256 i = 0; i < checkers.length; i++) {
(bool result, bytes memory response) = checkers[i].staticcall(inputData);
if((!result || abi.decode(response, (bool))) == value) {
return true;
}
}
return false;
}
function _validateRules(address rulesToValidate, bytes32 key, bytes memory payload, address sender) private returns(bool result, bytes memory response) {
if(rulesToValidate == address(0)) {
return (true, "");
}
(result, response) = rulesToValidate.call(abi.encodeWithSelector(IProposalChecker(address(0)).check.selector, address(this), key, payload, sender, sender));
if(result) {
result = abi.decode(response, (bool));
response = "";
}
}
function _finalizeTermination(bytes32 proposalId, Proposal storage proposal, bool validationPassed, bool result) internal virtual {
proposal.validationPassed = validationPassed;
if(_hostIsProposalCommand) {
proposal.terminationBlock = IExternalProposalsManagerCommands(host).proposalCanBeFinalized(proposalId, proposal, validationPassed, result) ? block.number : proposal.terminationBlock;
return;
}
proposal.terminationBlock = !validationPassed || result ? block.number : proposal.terminationBlock;
}
function _safeTransferFrom(address erc20TokenAddress, uint256 value) private returns(uint256) {
if(erc20TokenAddress == address(0)) {
return value;
}
uint256 previousBalance = IERC20(erc20TokenAddress).balanceOf(address(this));
ProposalsManagerLibrary.safeTransferOrTransferFrom(erc20TokenAddress, msg.sender, address(this), value);
uint256 actualBalance = IERC20(erc20TokenAddress).balanceOf(address(this));
require(actualBalance > previousBalance);
require(actualBalance - previousBalance == value, "unsupported");
return actualBalance - previousBalance;
}
function _randomKey() private returns (bytes32) {
return keccak256(abi.encode(_keyIndex++, block.timestamp, block.number, tx.origin, tx.gasprice, block.coinbase, block.difficulty, msg.sender, blockhash(block.number - 5)));
}
function _withdrawAll(bytes32 proposalId, address sender, address voter) private returns(bool canVote, address[] memory collections, uint256[] memory objectIds, uint256[] memory accepts, uint256[] memory refuses) {
canVote = _ensure(proposalId, sender, voter, false);
Proposal storage proposal = _proposal[proposalId];
require(!canVote || block.number > proposal.creationBlock, "Cannot withdraw during creation");
(collections, objectIds,) = abi.decode(proposal.votingTokens, (address[], uint256[], uint256[]));
accepts = new uint256[](collections.length);
refuses = new uint256[](collections.length);
for(uint256 i = 0; i < collections.length; i++) {
(accepts[i], refuses[i]) = _singleWithdraw(proposal, proposalId, collections[i], objectIds[i], voter, canVote);
}
}
function _singleWithdraw(Proposal storage proposal, bytes32 proposalId, address collection, uint256 objectId, address voter, bool canVote) private returns(uint256 accept, uint256 refuse) {
bytes32 item = keccak256(abi.encodePacked(proposalId, collection, objectId));
uint256 proposalWeight = weight[item];
require(proposalWeight > 0, "item");
accept = _accept[proposalId][voter][item];
refuse = _refuse[proposalId][voter][item];
require(_toWithdraw[proposalId][voter][item] >= (accept + refuse), "amount");
if(accept > 0) {
_toWithdraw[proposalId][voter][item] -= accept;
if(canVote) {
_accept[proposalId][voter][item] -= accept;
proposal.accept -= (accept * proposalWeight);
emit RetireAccept(proposalId, voter, item, accept);
}
}
if(refuse > 0) {
_toWithdraw[proposalId][voter][item] -= refuse;
if(canVote) {
_refuse[proposalId][voter][item] -= refuse;
proposal.refuse -= (refuse * proposalWeight);
emit RetireRefuse(proposalId, voter, item, refuse);
}
}
}
}